13

我确信有一个简单的答案,但现在是星期五下午,我累了。:(

不知道如何解释它,所以我将继续发布示例代码......


这是一个简单的对象:

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( <CurrentObject>.Stuff + $j(<CallerElement>).attr('id') );
    }

(其中<CurrentObject><CallerElement>替换为适当的名称。)

4

4 回答 4

24

这不是 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 的事件处理程序设置器:它不再与 Bob 或任何其他对象有任何连接,因此 JavaScript 会传入全局window对象。(这是 JavaScript 最糟糕的设计特性之一,因为你可能不会立即注意到它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))
            );
        };
    };
}
于 2009-10-09T16:45:56.060 回答
8

改变

$('#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 );
        }
}
于 2009-10-09T16:16:33.697 回答
5

的身份this是javascript中的一个常见问题。如果您尝试创建以下快捷方式,它也会中断doSomething

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

不依赖this. 您可以通过多种方式做到这一点,但最简单的方法是显式引用Bob而不是thisdoSomething. 另一种是使用构造函数(但是你会失去很酷的对象文字语法):

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();
于 2009-10-09T16:50:57.250 回答
0

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

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

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

于 2010-04-22T14:54:01.167 回答