提问人:Chris MacDonald 提问时间:10/8/2008 更新时间:12/23/2011 访问量:54543
JavaScript 回调范围 [duplicate]
JavaScript Callback Scope [duplicate]
问:
我在使用普通的旧 JavaScript(没有框架)在回调函数中引用我的对象时遇到了一些问题。
function foo(id) {
this.dom = document.getElementById(id);
this.bar = 5;
var self = this;
this.dom.addEventListener("click", self.onclick, false);
}
foo.prototype = {
onclick : function() {
this.bar = 7;
}
};
现在,当我创建一个新对象时(在DOM加载之后,使用span#test)
var x = new foo('test');
onclick 函数中的 'this' 指向 span#test,而不是 foo 对象。
如何在 onclick 函数中获取对我的 foo 对象的引用?
答:
this.dom.addEventListener("click", function(event) {
self.onclick(event)
}, false);
评论
function () {var i; for (i=0; i<5; i++) { setTimeout( function() { console.log(i); }, 1000); } }; f();
var self
function f()
)
这是 JS 最令人困惑的点之一:“this”变量表示最局部的对象......但函数也是对象,所以“this”指向那里。还有其他微妙的点,但我不记得它们了。
我通常避免使用“this”,只需定义一个局部的“me”变量并改用它。
评论
this
this
(提取了一些隐藏在其他答案评论中的解释)
问题出在以下行:
this.dom.addEventListener("click", self.onclick, false);
在这里,你传递一个函数对象作为回调。当事件触发时,该函数被调用,但现在它与任何对象 (this) 都没有关联。
可以通过将函数(及其对象引用)包装在闭包中来解决此问题,如下所示:
this.dom.addEventListener(
"click",
function(event) {self.onclick(event)},
false);
由于变量 self 是在创建闭包时分配的,因此闭包函数将在稍后调用 self 变量时记住该变量的值。
解决此问题的另一种方法是创建一个效用函数(并避免使用变量来绑定它):
function bind(scope, fn) {
return function () {
fn.apply(scope, arguments);
};
}
更新后的代码将如下所示:
this.dom.addEventListener("click", bind(this, this.onclick), false);
Function.prototype.bind
是 ECMAScript 5 的一部分,提供相同的功能。因此,您可以执行以下操作:
this.dom.addEventListener("click", this.onclick.bind(this), false);
对于尚不支持 ES5 的浏览器,MDN 提供了以下填充码:
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5 internal IsCallable function
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(this instanceof fNOP
? this
: oThis || window,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
评论
解释是,这并不意味着你认为它在 JavaScript 中的含义。它实际上意味着对象原型中的函数(不以任何方式引用自身)。self.onclick
onclick
self
self
JavaScript 只有函数,没有像 C# 那样的委托,因此不可能传递方法和它应该作为回调应用到的对象。
在回调中调用方法的唯一方法是在回调函数中自行调用它。由于 JavaScript 函数是闭包,因此它们能够访问在创建它们的范围内声明的变量。
var obj = ...;
function callback(){ return obj.method() };
something.bind(callback);
评论
我写了这个插件...
我认为这将是有用的
这里提供了对问题的一个很好的解释(我在理解到目前为止描述的解决方案时遇到了问题)。
对于寻求此问题解决方案的jQuery用户,您应该使用jQuery.proxy
评论
this.cb = this.onclick.bind(this); addEventListener("click", this.cb);