2011-07-21 118 views
2

我的代码:的Javascript范围和调用函数

for (var i = 0; i < mapInfos.length; i++) { 

      var x = function() { doStuff(i); }; 
      google.maps.event.addListenerOnce(mapInfos[i].map, 'tilesloaded', x); 
} 

的doStuff方法只是简单地提醒我的价值。 mapInfos有两个条目,所以你希望它提醒0和1,但它会提醒2和2.我可以隐约地理解它为什么这样做(尽管var我应该保持它在本地的循环范围?)但我怎样才能使其按预期工作?

+1

Doh-我甚至猜不出这个问题以前有多频繁。 – jAndy

+0

[你原来的jsfiddle](http://jsfiddle.net/RG3GR/)就是一个很好的例子。 – Pointy

回答

8

编辑 —注意,第一次发布时,包括原来的问题一个link to a jsfiddle这似乎是什么的问题,目前正在努力实现一个相关的例子,只是它的工作原理。


jsfiddle中的代码工作,因为该代码中只有一个“我”。第二个循环中使用的“i”(实际调用函数的地方)与第一个循环中使用的“i”相同。因此,你得到了正确的答案,因为第二个循环通过从零到四个再次的所有值运行“i”。如果你添加了:

i = 100; 
functions[0](); 

你会得到100打印出来。

在JavaScript中引入新范围的唯一方法是一个函数。一种方法是写一个单独的“功能机”的功能:

function makeCallback(param) { 
    return function() { 
    doStuff(param); 
    }; 
} 

然后在您的循环:因为调用了“makeCallback”功能隔离一个副本

for (var i = 0; i < mapInfos.length; i++) { 
    var x = makeCallback(i); 
    google.maps.event.addListenerOnce(mapInfos[i].map, 'titlesloaded', x); 
} 

这会工作将“i”的值转换为返回的闭包中新的唯一“param”实例。

+0

什么jsfiddle?什么第二回路? – Quentin

+0

@Quentin问题首次发布时,有一个jsfiddle链接。它与我在问题中添加的评论相关联。这是一段有趣的代码:-) – Pointy

+0

对不起,我很快注意到与回答put的人相同的东西,并删除了JSFiddle,因为它没有证实我的问题的其余部分:) – NibblyPig

1

为它创建一个新的范围。

函数创建范围。

function doStuffFactory(i) { 
    return function() { doStuff(i); }; 
} 

for (var i = 0; i < mapInfos.length; i++) { 
    var x = doStuffFactory(i); 
    google.maps.event.addListenerOnce(mapInfos[i].map, 'tilesloaded', x); 
} 
+0

eehhr ...'google.maps.event.addListenerOnce(mapInfos [i] .map,'tilesloaded',doStuff(i));'? – jAndy

+1

@jAndy:你现在传递调用该​​函数的结果,而不是对它的引用。 –

+0

@Tomalak:够公平的,记下我自己。 – jAndy

1

将其更改为

var x = function (param) { doStuff(param); }; 

显然正在发生的事情是,你是在提醒被改变的变量。通过上述更改,即使我更改了它,它仍会提醒正确的值。

0

的Javascript 有块范围,所以你得到x局部于循环。是啊!

虽然它有功能范围。

0

是的,奇怪的是吧!尖有一个解释

我不知道为什么你的第一个例子中的工作(我没想到它) 尖有,为什么你的第一个例子曾解释 - 之所以你的第二个没有,是因为i的作用域是包含for循环的函数,而不是由for循环定义的作用域。事实上,只有JavaScript中有作用域的东西才是函数。这意味着当你的函数执行时i2

你需要做的是创建一个范围,例如:

for (var i = 0; i < mapInfos.length; i++) { 

    var x = (function() { 
     return function() { doStuff(i); }; 
    })(i); 
    google.maps.event.addListenerOnce(mapInfos[i].map, 'tilesloaded', x); 
} 

更多见JavaScript closures in for-loops