无法创建javascript闭包

时间:2013-04-22 11:53:03

标签: javascript syntax scope closures

尝试在test.tgt中创建与test.src中的函数相同的函数,除了它们将具有上下文。

test.src.fn() => test.work.fn.call(context)

这是试验台

var fn1 = function() { console.log( 'fn1' ); }; 
var fn2 = function() { console.log( 'fn2' ); }; 
var context = { a: 1 };
var test = {
  tgt: {},
  src: { one: fn1, two: fn2 },
  init: function() {
    for( var i in test.src ) {
      test.tgt[i] = function(arg) { test.src[i].call(test.cxt,arg); };
    }
  }
}
test.init();
test.src.one() => 'fn1'
test.tgt.one() => 'fn2'   ouch!!

问题是在执行函数之前不会评估test.src[i]

如何获得"真实" test.src[i]在新创建的函数中?

3 个答案:

答案 0 :(得分:2)

尝试为循环的每次迭代创建一个闭包:

var fn1 = function() { console.log( 'fn1' ); }; 
var fn2 = function() { console.log( 'fn2' ); }; 
var context = { a: 1 };
var test = {
  tgt: {},
  src: { one: fn1, two: fn2 },
  init: function() {
    for( var i in test.src ) {
      test.tgt[i] = (function(index){return function(arg) { test.src[index].call(test.cxt,arg); };}(i));
    }
  }
}
test.init();
test.src.one() // => 'fn1'
test.tgt.one() // => 'fn1'

答案 1 :(得分:2)

这是一个经典的Javascript问题。您假设for循环的上下文中的i应该被捕获为创建函数时的值,而不是它的最后一个值。为了解决这个问题,您可以在本地捕获它:

test.tgt[i] = (function(local_i){
    return function(arg) { test.src[local_i].call(test.cxt,arg); };
})(i);

所以你将它包装在一个立即执行的函数上下文中,内部函数为该迭代获得正确的i值。

答案 2 :(得分:1)

您在init内创建的所有函数都有共享闭包,因此它们共享i变量,因此它始终是最后一个。试试这个:

init: function() {
    for( var i in test.src ) {
      (function(idx) { 
          test.tgt[idx] = function(arg) {test.src[idx].call(test.cxt,arg); };
      }(i));
    }
}