这不是 jQuery 的错,它是 JavaScript 处理对象的方式不可或缺的一部分。
与大多数其他面向对象语言不同,“this”是not在 JavaScript 中绑定在每个方法级别;相反,它纯粹由函数的调用方式决定:
Bob= {
toString: function() { return 'Bob!'; },
foo: function() { alert(this); }
};
Brian= {
toString: function() { return 'Brian!'; },
};
Bob.foo(); // Bob!
Bob['foo'](); // Bob!
Brian.foo= Bob.foo;
Brian.foo(); // Brian! NOT Bob
var fn= Bob.foo;
fn(); // window NOT Bob
在以下情况下您正在做什么:
$j('#MyButton').click( Bob.doSomething );
就像最后一个例子一样fn
:您正在拉动该功能doSomething
离开 Bob 并将其作为纯函数传递给 jQuery 的事件处理程序设置器:它不再与 Bob 或任何其他对象有任何连接,因此 JavaScript 传入全局window
对象代替。 (这是 JavaScript 最糟糕的设计功能之一,因为您可能不会立即注意到window
isn't Bob
,并开始访问其属性,导致奇怪且令人困惑的交互和错误。)
为了记住 Bob,您通常会像 nickyt 的答案一样创建一个函数,在闭包中保留“Bob”的副本,以便在回调时记住它并用于调用真正的方法。然而,现在 ECMAScript 第五版中有一种标准化的方法可以做到这一点:
$j('#MyButton').click( Bob.doSomething.bind(Bob) );
(您还可以在bind
打电话去打电话doSomething
和他们一起回来,这很方便。)
对于尚未原生支持第五版的 bind() 方法的浏览器(目前是大多数浏览器),您可以修改您自己的实现bind
(原型库也这样做),例如:
if (!Object.bind) {
Function.prototype.bind= function(owner) {
var that= this;
var args= Array.prototype.slice.call(arguments, 1);
return function() {
return that.apply(owner,
args.length===0? arguments : arguments.length===0? args :
args.concat(Array.prototype.slice.call(arguments, 0))
);
};
};
}