尽管函数包装,值仍未在循环中关闭

时间:2015-03-19 21:26:49

标签: javascript closures

我有一个我正在循环的对象列表;这些对象中的每一个都有一个属性,它是一个引用this的函数。如果我根据我的对象创建一个回调列表,似乎我必须"双重包装" this - 依赖函数,以维护正确的引用。我不明白为什么会这样 - 有人可以解释一下吗?

function Pokemon(name) {
    this.name = name;
    this.sayName = function() {
        console.log(this.name);
    };
}

function runFunctions(arrayOfFunctions) {
    for (var i = 0, fn; fn = arrayOfFunctions[i]; i++) {
        fn();
    }
}

var monsters = [
    new Pokemon('Charmander'), 
    new Pokemon('Squirtle'),
    new Pokemon('Bulbasaur')
];

var unclosedCalls = [];
var closedCalls = [];

for (var i = 0, monster; monster = monsters[i]; i++) {
    var unclosedCall = (function(m) {
            return m.sayName
        })(monster);

    var closedCall = (function(m) {
            return function() {
                m.sayName();
            }
        })(monster);

    unclosedCalls.push(unclosedCall);
    closedCalls.push(closedCall);
}

console.log('--start')
runFunctions(unclosedCalls); // doesn't work
console.log('----')
runFunctions(closedCalls); // works
console.log('--end')

closedCalls是双包装回调列表。

我不明白为什么在m的每次创作中unclosedCall实际上都没有被关闭。

这是一个带有我的代码的jsbin:http://jsbin.com/qivilusuje/1/edit?js,console,output

1 个答案:

答案 0 :(得分:1)

"未关闭"的问题调用是您返回的函数引用(m.sayName)立即与从中检索函数属性的变量m取消关联。

函数引用并不知道从哪个对象检索它,所以当函数最终被调用时它没有" context" - this将设置为全局对象,而不是最初将此函数作为属性的对象:

var obj = {
    func : function() { console.log(this) }
}

obj.func() // outputs "obj" because a.b() calls "b" with "this" === "a"
var ref = obj.func;
ref();     // outputs "window"

要解决这个问题,你可以进行未结算的电话return m.sayName.bind(m),虽然已经到了那里,但也不需要IIFE,并且可以说:

var unclosedCall = monster.sayName.bind(monster);