【问题标题】:Javascript callbacks losing 'this'Javascript回调丢失'this'
【发布时间】:2012-05-26 12:54:57
【问题描述】:

我有一个发行者,我在这个“对象”中丢失了“这个”。下面一段 javascript 的输出给了我“some-id”,然后是“undefined”。当我在回调函数中使用“this”时,范围超出了对象,它不能再使用“this”了。如何让回调使用“this”或至少可以访问该对象?

由于我将制作多个对象,因此我将无法创建类似“静态”的存储。请帮助这个 javascript n00b ;-)

这是我的测试代码,您可以使用它来重现我的问题。我想要的是 CheckBox.doSomething() 返回 this.id 的值,该值应该与此测试用例的 some-id 匹配。

function CheckBox(input_id) {
    this.id = input_id;
    this.doSomething();
    $('#some-element').click(this.doSomething);
}

Checkbox.prototype.doSomething = function() {
    alert(this.input_id);
}

var some_box = new CheckBox('some-id');
some_box.doSomething();
$('#some-element').click();

编辑:我什至无法按照我的意愿让它工作:

function CheckBox2(input_id) {
    this.id = input_id;
    alert(this.id);
}

CheckBox2.prototype.doSomething = function() {
    alert(this.input_id);
}
var some_box = new CheckBox2('some-id');
some_box.doSomething();

【问题讨论】:

标签: javascript object callback this scope


【解决方案1】:

你的问题在于这一行:$('#some-element').click(this.doSomething);

为什么这是个问题

JavaScript 方法对应该分配给 this 的对象一无所知,它是在显式(使用 myFunction.call(obj))或隐式调用(使用 obj.myFunction() 调用)时设置的。

例如:

var x = {
    logThis: function () {
        console.log(this);
    }
};

x.logThis(); // logs x
x.logThis.call(y); // logs y

var func = x.logThis;
func(); // logs window: the fallback for when no value is given for `this`

在您的情况下,您将 this.doSomething 传递给 jQuery,然后使用被单击的元素作为 this 的值显式调用它。正在发生的事情是(稍微复杂一点的)这个:

var callback = this.doSomething;
callback.call(anElement, anEvent);

解决办法

您需要确保使用正确的 this 值调用 doSomething。您可以通过将其包装在另一个函数中来做到这一点:

var cb = this;
$('#some-element').click(function() {
    return cb.doSomething();
});

jQuery 提供了一个proxy 函数让您更简单地做到这一点:

$('#some-element').click(jQuery.proxy(this.doSomething, this));

【讨论】:

  • 在这种情况下,some_box.doSomething(); 在我调用它时已经给了我“未定义”。这怎么可能?我没有在那里使用任何回调
  • 您的代码中有一个错字:在构造函数中您设置了this.id,但在doSomething 函数中您引用了this.input_id
  • 我会更加强调使用 $.proxy,它允许你的类是可扩展的,并将所有功能整齐地保存在原型中
  • @Esailija:我认为理解代码为什么不起作用比仅仅知道解决问题的具体方法更有益。如果您打算使用this.func = $.proxy(this.func, this) 之类的技巧,那么您应该真正了解它的工作原理和原因,我相信您会这样做,但其他阅读您答案的人可能不会。
  • @georgebrock 我并不是要与我的答案进行比较,只是想指出说函数绑定只是一种更简单的方法是轻描淡写的,因为它还有很多其他好处。无论如何,你的答案显然更好。
【解决方案2】:
function CheckBox(input_id) {
    this.id = input_id;
    this.doSomething = $.proxy( this.doSomething, this );
    $('#some-element').click(this.doSomething);
}

这个的“javascript 等价物”是Function#bind,但这并不是在每个浏览器中都可用,因为看起来你使用的是 jQuery,所以我使用的是 jQuery 等价物$.proxy

【讨论】:

  • 是的,我可以看到.. 1 天的 JavaScript 太多:3 非常感谢!现在我明白了为什么我之前使用不同的创建对象的方法遇到了很多未定义变量的问题。感谢您提供清晰的示例
【解决方案3】:

其他人已经解释了问题的原因以及如何使用 jQuery 修复它。剩下的就是如何使用标准 JavaScript 修复它。而不是...

$('#some-element').click(this.doSomething);

...你写:

document.getElementById('some-element').addEventListener('click', this.doSomething.bind(this));

这会改变thisdoSomething 中的上下文。您也可以使用匿名函数来做到这一点 - 而不是 ...

$('#some-element').click(function(event) {
    console.log(this);
});

...你写:

document.getElementById('#some-element').addEventListener('click', (function(event) {
    console.log(this);
}).bind(this));

这在有很多回调的项目中对我非常有用,例如在 Node.js 中(您不必关心过时的浏览器)。

编辑:getElementById()addEventListener() 而不是 $(...).click(...)

【讨论】:

    猜你喜欢
    • 2017-02-18
    • 1970-01-01
    • 2017-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-01
    • 1970-01-01
    • 2012-12-24
    相关资源
    最近更新 更多