我有一个对象"我"为其定义的功能。
me.prototype.f = function(args){
console.log("f called");
};
我需要在异步函数中提供f作为回调。
me.prototype.operation = function (){
var self = this;
var client; // an io client
//client.on("data", self.f); --a
//client.on("data", self.f.bind(self)) --b
}
和&之间有什么区别吗? b在这种情况下,是否存在a)可能失败的情况?
在哪些情况下,我们会在没有绑定的情况下遇到问题?通常情况下,值可能会根据上下文而改变。 (例如,使用循环索引值进行闭包)
那么,值可能采取不同行为的不同场景可能是什么。
从答案中我得出以下结论。请确认一下:
a)范围将随着函数作为引用传递而更改,并将获取本地引用,除非上下文未使用bind,call或apply绑定。
b)特别是在回调/异步函数中,如果更改了上下文(例如setTimeout,则上下文会发生变化,因此self的含义会在调用期间发生变化。)
c)它与闭包无关,因为在闭包中检查词法环境是否有评估值,但是,这里评估执行时的上下文
答案 0 :(得分:1)
self.f
是对f
函数的引用。
self.f.bind(self)
是一个新功能,在调用时调用f
self
为this
。
和&之间有什么区别吗?在这种情况下,上面是b并且在那里 a)可能失败的任何情况?
是。行为取决于您如何进行通话:
function me() {}
me.prototype.f = function() {
console.log(this);
};
me.prototype.operation = function() {
client.on("this.f", this.f);
client.on("this.f.bind(this)", this.f.bind(this));
};
var client = {
on: function(whatever, callback) {
var self = this;
setTimeout(function() {
console.log("=== " + whatever + " ===");
self.f = callback;
// `this` not specified
// `this.f` logs the global object, or `undefined` in strict mode
// `this.f.bind(this)` logs `me` instance
callback();
// `this` belongs to current function (passed to setTimeout)
// `this.f` logs the global object, or `undefined` in strict mode
// `this.f.bind(this)` logs `me` instance
callback.call(this);
// `self` is a reference to the client object
// `this.f` logs `client`
// `this.f.bind(this)` logs `me` instance
callback.call(self);
// `this` is determined by the calling object (client again)
// `this.f` logs `client`
// `this.f.bind(this)` logs `me` instance
self.f();
}, 1000);
}
};
(new me()).operation();
我已经决定在答案中添加更多内容,因为您已经在问题中添加了更多内容。很遗憾,结果很长。
this
如何运作 this
的值是在函数调用时确定的,而不是在函数定义上确定的。
调用不属于对象this
的属性的函数时
将是undefined
严格,或引用全局对象
非严格模式。
function f1() {
console.log(this === window);
}
function f2() {
'use strict';
console.log(this === undefined);
}
f1(); // true
f2(); // true
调用作为对象属性的函数时,this
将引用该对象。
var object = {
f: function() {
console.log(this === object);
}
};
object.f(); // true
调用带有new
前缀的函数时,this
将引用
新创建的对象。
var backup;
function Example() {
backup = this;
this.value = 0;
}
var example = new Example();
console.log(example === backup); // true
console.log(example.value); // 0
调用不是对象属性的函数时,但是
是对象原型链的一部分,this
将引用
调用对象。
function Example() {}
Example.prototype.f = function() {
console.log(this === example);
};
var example = new Example();
example.f(); // true
this
提到的行为往往不是我们想要的。请考虑以下情况。
function Counter() {
this.count;
this.limit;
this.interval;
}
Counter.prototype.countTo = function(number) {
this.count = 1;
this.limit = number;
this.interval = setInterval(update, 1000);
function update() {
console.log(this.count);
if (++this.count > this.limit)
clearInterval(this.interval);
}
};
var counter = new Counter();
counter.countTo(5); // undefined, NaN, NaN, NaN, NaN, NaN...
调用函数后,
this
会获取其值,而不是在定义函数时。稍后将调用interval函数,this
将引用全局对象。在大多数情况下,这不是人们所追求的。
this
解决setInterval
问题的历史方法是将this
的引用分配给有问题的函数可见的变量,然后使用该变量。
function Counter() {}
Counter.prototype.countTo = function(number) {
this.count = 1;
this.limit = number;
var self = this;
function update() {
console.log(self.count);
if (++self.count > self.limit)
clearInterval(self.interval);
}
this.interval = setInterval(update, 1000);
};
var counter = new Counter();
counter.countTo(5);
同样采用封闭式,防止污染功能范围。
function Counter() {}
Counter.prototype.countTo = function(number) {
this.count = 1;
this.limit = number;
this.interval = setInterval((function(self) {
return function() {
console.log(self.count);
if (++self.count > self.limit)
clearInterval(self.interval);
};
}(this)), 1000);
};
var counter = new Counter();
counter.countTo(5);
每当创建update
时创建新的Counter
函数并不是最有效的方法。假设我们想将其移至原型。
function Counter() {
this.count;
this.limit;
this.interval;
}
Counter.prototype.countTo = function(number) {
this.count = 1;
this.limit = number;
this.interval = setInterval(this.update, 1000);
};
Counter.prototype.update = function() {
console.log(this.count);
if (++this.count > this.limit)
clearInterval(this.interval);
};
var counter = new Counter();
counter.countTo(5); // undefined, NaN, NaN, NaN, NaN, NaN...
现在的问题是让update
了解self
,因为它们不再在同一范围内定义,并且所有{{1}只有一个update
函数}第
我们可以创建一个中介函数来包含Counter
的值(复制引用)并使用它来进行调用。
this
我们可以使用箭头函数,它在词法上绑定function Counter() {
this.count;
this.limit;
this.interval;
}
Counter.prototype.countTo = function(number) {
this.count = 1;
this.limit = number;
var update = (function(self) {
return function() {
self.update();
};
}(this));
this.interval = setInterval(update, 1000);
};
Counter.prototype.update = function() {
console.log(this.count);
if (++this.count > this.limit)
clearInterval(this.interval);
};
var counter = new Counter();
counter.countTo(5);
,也就是说,它的值是根据函数定义确定的,无论它是如何或何时被调用的。
this
function Counter() {
this.count;
this.limit;
this.interval;
}
Counter.prototype.countTo = function(number) {
this.count = 1;
this.limit = number;
this.interval = setInterval(() => this.update(), 1000); // neat.
};
Counter.prototype.update = function() {
console.log(this.count);
if (++this.count > this.limit)
clearInterval(this.interval);
};
var counter = new Counter();
counter.countTo(5);
假设我们的this
函数已在其他地方定义,我们希望使用它而不是原型函数。
update
使用前面提到的方法,我们可以在对象或其原型中附加对function Counter(to) {
this.count;
this.limit;
this.interval;
}
Counter.prototype.countTo = function(number) {
this.count = 1;
this.limit = number;
this.interval = setInterval(update, 1000);
};
function update() {
console.log(this.count);
if (++this.count > this.limit)
clearInterval(this.interval);
}
var counter = new Counter();
counter.countTo(5); // undefined, NaN, NaN, NaN, NaN, NaN...
的引用,并使用箭头函数绑定update
。如果我们不喜欢这种开销,我们可以使用三个强大的功能来明确设置this
:
在函数上调用this
会生成一个新函数,其bind
设置为第一个参数。
this
在函数上使用function Counter(to) {
this.count;
this.limit;
this.interval;
}
Counter.prototype.countTo = function(number) {
this.count = 1;
this.limit = number;
this.interval = setInterval(update.bind(this), 1000); // not bad.
};
function update() {
console.log(this.count);
if (++this.count > this.limit)
clearInterval(this.interval);
}
var counter = new Counter();
counter.countTo(5);
或call
会将apply
的调用设置为第一个参数。
this