JS对象this.method()通过jQuery中断

我相信这有一个简单的答案,但是周五下午,我很累。 🙁

不确定如何解释它,所以我将继续并发布示例代码…

这是一个简单的对象:

var Bob = { Stuff : '' , init : function() { this.Stuff = arguments[0] } , doSomething : function() { console.log( this.Stuff ); } } 

在这里它被使用:

 $j = jQuery.noConflict(); $j(document).ready( init ); function init() { Bob.init('hello'); Bob.doSomething(); $j('#MyButton').click( Bob.doSomething ); } 

一切正常,除了最后一行。 当jQuery调用doSomething方法时,它会覆盖’this’并阻止它工作。

试图只使用Stuff也不起作用。

那么如何以允许jQuery调用它的方式引用对象自己的属性,并且还允许该对象使用调用jQuery对象?

即我希望能够做到这样的事情:

 doSomething : function() { console.log( .Stuff + $j().attr('id') ); } 

(其中替换为适当的名称。)

this是javascript中的常见问题。 如果您尝试创建doSomething的快捷方式,它也会中断:

 var do = Bob.doSomething; do(); // this is no longer pointing to Bob! 

不依赖this身份是一种好习惯。 你可以通过各种方式做到这一点,但最简单的方法是明确引用Bob而不是doSomethingthis 。 另一个是使用构造函数(但是你失去了很酷的对象 – 文字语法):

 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(); 

这不是jQuery的错,它是JavaScript处理对象的方式的组成部分。

与大多数其他面向对象语言不同,’this’不受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的事件处理程序setter:它不再与Bob或任何其他对象有任何连接,因此JavaScript传入全局window对象代替。 (这是JavaScript最糟糕的设计function之一,因为您可能不会立即注意到window不是Bob ,并开始访问它上面的属性,导致奇怪和混乱的交互和错误。)

为了记住Bob,你通常会在nickyt的答案中创建一个函数,将’Bob’的副本保存在一个闭包中,以便在回调时记住它并用来调用真正的方法。 但是现在在ECMAScript第五版中有一种标准化的方法:

 $j('#MyButton').click( Bob.doSomething.bind(Bob) ); 

(你也可以在bind调用中添加额外的参数来调用doSomething ,这很方便。)

对于尚未支持第五版的bind()方法的浏览器(此时,大多数都是这些),你可以破解你自己的bind实现(Prototype库也这样做),类似于:

 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)) ); }; }; } 

更改

 $('#MyButton').click( Bob.doSomething ); 

 $('#MyButton').click( function() { Bob.doSomething() } ); 

您还可以向Bob对象添加一个私有字段var that = this并在成员的任何地方使用它而不是this如果您真的想要避免使用匿名函数。

例如

 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 ); } } 

你总是可以尝试做这样的事情:

 $j('#MyButton').click(function(event) { Bob.doSomething(event, this); }); 

现在doSomething仍然会有Bob this ,并且使用函数参数,它将拥有event对象,以及它被触发的元素。