JS对象this.method()通过jQuery中断
JS对象this.method()通过jQuery中断
我确定对于这个问题有一个简单的答案,但是现在是星期五下午,我很累。\n不确定如何解释,所以我将直接发布示例代码...\n以下是一个简单的对象:\n
var Bob = { Stuff : '' , init : function() { this.Stuff = arguments[0] } , doSomething : function() { console.log( this.Stuff ); } }
\n这是它的使用方式:\n
$j = jQuery.noConflict(); $j(document).ready( init ); function init() { Bob.init('hello'); Bob.doSomething(); $j('#MyButton').click( Bob.doSomething ); }
\n除了最后一行之外,一切正常。当jQuery调用doSomething方法时,它覆盖了\'this\'并阻止其工作。\n尝试仅使用Stuff
也不起作用。\n那么,如何以一种允许jQuery调用它的方式引用对象的自有属性,并使对象能够与调用的jQuery对象一起工作?\n即,我希望能够像这样做一些事情:\n
doSomething : function() { console.log(.Stuff + $j( ).attr('id') ); }
\n(其中
和
将被替换为适当的名称。)
在JavaScript中,this
的身份是一个常见的问题。如果你尝试创建一个指向doSomething
的快捷方式,它也会出现错误:
var do = Bob.doSomething; do(); // this is no longer pointing to Bob!
不依赖于this
的身份是一个好的实践。你可以通过多种方式来实现,但最简单的方法是在doSomething
内部显式地引用Bob
,而不是this
。另一种方法是使用构造函数(但这样你就失去了酷炫的对象字面量语法):
var createBob = function() { var that = {}; that.Stuff = ''; that.init = function() { that.Stuff = arguments[0]; }; that.doSomething = function() { console.log( that.Stuff ); }; return that; } var bob = createBob();
这似乎是最好的折中方案(尽管我的真实对象的名称要长得多,不幸的是)。鉴于我实际上是在'断开'从Bob到doSomething的连接,那么在doSomething内部引用Bob是否会有其他潜在的副作用呢?
在正常的使用中,不应该有副作用。你可能能够想出一个复杂的情况,其中你将Bob.doSomething赋值给一个变量,然后更改Bob的值,从而破坏你的doSomething快捷方式。然而,在实践中很少会遇到这种情况。我还增加了一个更封装的建议。
问题出现的原因是使用jQuery的click事件绑定方法时,使用了`this.method()`的语法,导致`this`指向了不正确的对象。解决方法是改用匿名函数来调用`Bob.doSomething()`,或者在Bob对象中添加一个私有字段`that`来代替`this`的使用。
具体解决方法如下:
$('#MyButton').click(function() { Bob.doSomething(); });
或者在Bob对象中添加私有字段`that`:
var Bob = new function() { // Private Fields var that = this; // Public Members this.Stuff = ''; this.init = function() { that.Stuff = arguments[0]; } this.doSomething = function() { console.log(that.Stuff); } }
这样做的原因是,jQuery在执行回调函数时会将`this`绑定为触发事件的元素,因此它试图执行`someElement.doSomething()`。但是这样做很丑陋,而且如果想访问调用对象的jQuery对象,就无法实现了。
对于问题的进一步澄清,使用上述方法将阻止`doSomething`方法了解到是`#MyButton`调用了它,这并不是本意。尝试在匿名函数中传递`arguments`会导致嵌套的参数,这是不可取的。因此,希望能有更好的解决方案。
JS Object this.method() breaks via jQuery是一个关于JavaScript对象和jQuery之间交互的问题。出现这个问题的原因是JavaScript中的this关键字的特性。与其他大多数面向对象语言不同,JavaScript中的this关键字并不是在每个方法级别上绑定的,而是纯粹由函数的调用方式决定。
在给定的例子中,当我们执行Bob.foo()时,this指向了Bob对象。但是当我们执行Brian.foo()时,this指向了全局的window对象,而不是Bob对象。这是因为在调用Bob.foo()时,this是由Bob对象调用的,但在调用Brian.foo()时,this是由Brian对象调用的(Brian对象是Bob对象的一个副本,但它并不具有Bob对象的方法)。
在使用jQuery的事件处理器时,如果我们像下面这样传递一个函数给click()方法:
$j('#MyButton').click( Bob.doSomething );
此时的doSomething函数已经与Bob对象断开了联系,它被作为一个纯函数传递给了jQuery的事件处理器。因此,JavaScript将全局的window对象作为this传递给了doSomething函数,而不是Bob对象。这就会导致在函数内部访问window对象的属性,从而引发一些奇怪和混乱的错误。
为了解决这个问题,我们可以使用闭包来保存Bob对象的副本,以便在回调时记住它并用于调用真正的方法。在ECMAScript第五版中,引入了一个标准的方法来实现这个目的:
$j('#MyButton').click( Bob.doSomething.bind(Bob) );
通过调用bind()方法,我们将Bob对象绑定到doSomething方法,这样在回调时就可以正确地访问Bob对象。
对于那些尚未原生支持bind()方法的浏览器(目前大多数浏览器都不支持),可以使用自己实现的bind()方法。例如,Prototype库提供了自己的实现。下面是一个简单的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))
);
};
};
}
总结起来,避免使用this关键字是一个简单的解决方法,但在某些情况下可能并不容易实现。因此,使用bind()方法是一种更为通用和标准的解决方案,可以确保在不同的浏览器环境下都能正常工作。