Javascript:在 For 循环中创建函数

标签 javascript function

最近,我发现自己需要创建一个函数数组。这些函数使用 XML 文档中的值,我使用 for 循环遍历适当的节点。然而,在这样做时,我发现数组中的所有函数只使用了 XML 表的最后一个节点(对应于 for 循环的最后一次运行)。

下面是一个展示这一点的例子:

var numArr = [];
var funArr = [];
for(var i = 0; i < 10; ++i){
    numArr[numArr.length] = i;
    funArr[funArr.length] = function(){  return i; };
}

window.alert("Num: " + numArr[5] + "\nFun: " + funArr[5]());

输出为 Num:5 和 Fun:10。

经过研究,我发现了一个 a segment of code that works ,但我很难准确理解它为何起作用。我在这里使用我的示例复制了它:

var funArr2 = [];
for(var i = 0; i < 10; ++i)
    funArr2[funArr2.length] = (function(i){ return function(){ return i;}})(i);

window.alert("Fun 2: " + funArr2[5]());

我知道它与范围界定有关,但乍一看,它的表现似乎与我天真的方法没有任何不同。我是 Javascript 的初学者,所以如果我可能会问,为什么使用这种函数返回函数技术可以绕过作用域问题?另外,为什么 (i) 包含在最后?

非常感谢您。

最佳答案

如果使用不屏蔽循环变量名的参数名,第二种方法会更清晰一些:

funArr[funArr.length] = (function(val) { return function(){  return val; }})(i);

您当前代码的问题是每个函数都是一个 closure它们都引用相同的变量 i。当每个函数运行时,它返回函数运行时 i 的值(这将比循环的限制值大 1)。

更清晰的方法是编写一个单独的函数来返回您想要的闭包:

var numArr = [];
var funArr = [];
for(var i = 0; i < 10; ++i){
    numArr[numArr.length] = i;
    funArr[funArr.length] = getFun(i);
}

function getFun(val) {
    return function() { return val; };
}

请注意,这与我的回答中的第一行代码基本相同:调用一个返回函数的函数并将 i 的值作为参数传递。它的主要优点是清晰。

编辑:现在几乎所有地方都支持 EcmaScript 6(抱歉,IE 用户),您可以使用更简单的方法——使用 let 关键字而不是 var 循环变量:

var numArr = [];
var funArr = [];
for(let i = 0; i < 10; ++i){
    numArr[numArr.length] = i;
    funArr[funArr.length] = function(){  return i; };
}

有了这个小改动,每个 funArr 元素都是一个闭包边界,在每次循环迭代时执行一个不同 i 对象。有关 let 的更多信息,请参阅 this Mozilla Hacks post from 2015 . (如果您的目标环境不支持 let,请坚持我之前写的内容,或者在使用前通过转译器最后运行它。

关于Javascript:在 For 循环中创建函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19696015/

相关文章:

javascript - Angular 自定义空闲计时器

javascript - 在 GeoJson 数据接收到的 Google map 多边形上放置标签

javascript - 为什么添加bootstrap后代码不工作

javascript - js数+1问题

swift - 如何在每次更改所提供参数的值时迭代函数

javascript - 模板文字(模板字符串)没有在箭头函数中给出确切的结果

javascript - 具有可点击的父 div 和可点击的子 div

c++ - 在 C++ 函数调用中使用自增运算符是否合法?

c - 使用指向指针的指针时出现段错误

python - 一次性导入所有子模块