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

IT技术 javascript jquery json this
2021-03-13 10:20:36

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

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


这是一个简单的对象:

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个回答

这不是 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

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

$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() 方法的浏览器(在这一点上,这是其中的大部分),您可以在自己的实现中进行 hack 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))
            );
        };
    };
}
这些都是非常有用的信息,但我发现this首先避免使用通常更容易
2021-05-03 10:20:36
感谢您的详尽解释......虽然听起来我不会完全管理我想要的。:(
2021-05-12 10:20:36

改变

$('#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 );
        }
}
丑陋的。另外,我如何访问调用对象的 jQuery 对象?
2021-04-22 10:20:36
我已经澄清了这个问题 - 默认情况下,这个建议会阻止doSomething知道#MyButton调用它,这不是意图,并且会$j('#MyButton').click( function(){Bob.doSomething(arguments)} );导致嵌套参数,这是令人讨厌的,所以我希望有一个更好的解决方案。
2021-05-08 10:20:36
澄清为什么会这样:jquery 绑定this为在执行回调时触发事件的元素。因此它试图执行someElement.doSomething()
2021-05-15 10:20:36

的身份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();
这似乎是最好的妥协(尽管不幸的是,我的真实对象的名称要长得多)。鉴于我有效地将 doSomething 与 Bob 断开连接,在 doSomething 中引用 Bob 是否有任何其他潜在的副作用?
2021-04-24 10:20:36
@Peter 它不应该在正常使用中。您可能会想出一个复杂的场景,将 Bob.doSomething 分配给一个变量,然后更改 Bob 的值,从而打破 doSomething 的捷径。但是,这些通常不会在实践中出现。我还添加了第二个更封装的建议。
2021-05-16 10:20:36

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

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

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