处理程序中的JavaScript变量可见性

时间:2013-04-10 19:29:02

标签: javascript node.js

我对这是如何工作有点困惑,让我给你发一个示例代码:

someClass = function() {
    this.a = 10;

    this.Foo = function() {
        console.log(this.a); // will output "10"
        setTimeout(this.Bar, 1);
    }

    this.Bar = function() {
        console.log(this.a); // undefined
    }
}
var instance = new someClass();
instance.Foo();

我的理解是,如果从setTimeout(或其他一些"处理程序"类型的东西)中调用它,则函数栏中不会显示this.a。 解决这个问题的常见/正确方法是什么?

(我在Node.js btw中尝试这个)

谢谢。

2 个答案:

答案 0 :(得分:2)

当将函数 this.Bar 作为参数传递给另一个函数时,您需要绑定 this.Bar 到您的上下文d喜欢用它来执行。

如果你正在使用像jQuery或Underscore.js这样的JS库,他们已经拥有了这个功能:

setTimeout(_.bind(this.Bar, this), 1);

以下是 bind 函数的简单实现:

var bind = function(scope, fn) {
  return function() {
    return fn.apply(scope, arguments);
  };
}

<强>更新

正如@generalhenry指出的那样,node.js已经在( Function.prototype.bind )中附带了一个 bind 函数,所以你可以在不添加自定义的情况下执行此操作 bind 函数也不是外部库:

setTimeout(this.Bar.bind(this), 1);

答案 1 :(得分:2)

问题是当您将函数传递给this时范围(setTimeout)会丢失。

这是修复它的最简单方法,通过闭包存储this作为参考,然后使用它。

// This uses _me_ everywhere for consistency, but the only place that really needs it 
// is within the Bar method. But consistency in this case makes your code more change-
// proof, say if someone calls setTimeout(instance.Foo, 1)
someClass = function() {

    var me = this;
    me.a = 10;

    me.Foo = function() {
        console.log(me.a); // will output "10"
        // setTimeout will cause me.Bar to be called with window as the context
        setTimeout(me.Bar, 1);
    }

    me.Bar = function() {
        // so we avoid using _this_ in here
        console.log(me.a); // 10
    }
}

更优雅的方法是使用Function.bind

someClass = function() {
    this.a = 10;

    this.Foo = function() {
        console.log(this.a); // will output "10"
        // the bind call will force it to use the first argument as `this`
        setTimeout(this.Bar.bind(this), 1);
    }

    this.Bar = function() {
        console.log(this.a); // undefined
    }
}