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

Pet*_*ton 13 javascript jquery json this

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

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


这是一个简单的对象:

var Bob =

{ Stuff : ''

, init : function()
    {
        this.Stuff = arguments[0]
    }

, doSomething : function()
    {
        console.log( this.Stuff );
    }

}
Run Code Online (Sandbox Code Playgroud)

在这里它被使用:

$j = jQuery.noConflict();
$j(document).ready( init );


function init()
{
    Bob.init('hello');

    Bob.doSomething();

    $j('#MyButton').click( Bob.doSomething );
}
Run Code Online (Sandbox Code Playgroud)

一切都有效,除了最后一行.当jQuery调用doSomething方法时,它会覆盖'this'并阻止它工作.

试图使用只是Stuff不起作用.

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

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

doSomething : function()
    {
        console.log( <CurrentObject>.Stuff + $j(<CallerElement>).attr('id') );
    }
Run Code Online (Sandbox Code Playgroud)

(在哪里<CurrentObject><CallerElement>替换为适当的名称.)

bob*_*nce 24

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

不像大多数其它面向对象的语言中,"这个"是结合在每个方法级在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
Run Code Online (Sandbox Code Playgroud)

在以下情况下您正在做什么:

$j('#MyButton').click( Bob.doSomething );
Run Code Online (Sandbox Code Playgroud)

就像最后一个例子fn:你将函数doSomething从Bob 中拉出来并将其作为纯函数传递给jQuery的事件处理程序setter:它不再与Bob或任何其他对象有任何连接,因此JavaScript会传入全局window对象.(这是JavaScript最糟糕的设计功能之一,因为您可能不会立即注意到它window没有Bob,并开始访问它上面的属性,导致奇怪和混乱的交互和错误.)

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

$j('#MyButton').click( Bob.doSomething.bind(Bob) );
Run Code Online (Sandbox Code Playgroud)

(你也可以在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))
            );
        };
    };
}
Run Code Online (Sandbox Code Playgroud)


nic*_*ine 8

更改

$('#MyButton').click( Bob.doSomething );
Run Code Online (Sandbox Code Playgroud)

$('#MyButton').click( function() { Bob.doSomething() } );
Run Code Online (Sandbox Code Playgroud)

您还可以向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 );
        }
}
Run Code Online (Sandbox Code Playgroud)


Gab*_*art 5

身份this是javascript中的常见问题.如果您尝试创建一个快捷方式,它也会破坏doSomething:

var do = Bob.doSomething;
do(); // this is no longer pointing to Bob!
Run Code Online (Sandbox Code Playgroud)

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

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();
Run Code Online (Sandbox Code Playgroud)