Javascript:在 For 循环中创建函数 [英] Javascript: Creating Functions in a For Loop

查看:49
本文介绍了Javascript:在 For 循环中创建函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近,我发现自己需要创建一个函数数组.这些函数使用来自 XML 文档的值,我正在使用 for 循环遍历适当的节点.但是,在执行此操作时,我发现数组中的所有函数都只使用了 XML 表的最后一个节点(对应于 for 循环的最后一次运行).

Recently, I found myself needing to create an array of functions. The functions use values from an XML document, and I am running through the appropriate nodes with a for loop. However, upon doing this, I found that only the last node of the XML sheet (corresponding to the last run of the for loop) was ever used by all of the functions in the array.

以下是展示这一点的示例:

The following is an example that showcases this:

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] + "
Fun: " + funArr[5]());

输出为 Num: 5 和 Fun: 10.

The output is Num: 5 and Fun: 10.

经过研究,我发现了一段代码有效,但我正在努力理解它为什么有效.我在这里用我的例子复制了它:

Upon research, I found a a segment of code that works, but I am struggling to understand precisely why it works. I reproduced it here using my example:

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) 包含在末尾?

I know it has to do with scoping, but at first glance it does not seem like it would perform any differently from my naive approach. I am somewhat of a beginner in Javascript, so if I may ask, why is it that using this function-returning-a-function technique bypasses the scoping issue? Also, why is the (i) included on the end?

非常感谢您.

推荐答案

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

The second method is a little clearer if you use a parameter name that does not mask the loop variable name:

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

您当前代码的问题在于每个函数都是一个 闭包,它们都引用同一个变量i.当每个函数运行时,它返回函数运行时i的值(将比循环的限制值多一).

The problem with your current code is that each function is a closure and they all reference the same variable i. When each function is run, it returns the value of i at the time the function is run (which will be one more than the limit value for the loop).

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

A clearer way would be to write a separate function that returns the closure that you want:

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 的值作为参数传递.它的主要优点是清晰度.

Note that this is doing basically the same thing as the first line of code in my answer: calling a function that returns a function and passing the value of i as a parameter. It's main advantage is clarity.

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

Now that EcmaScript 6 is supported almost everywhere (sorry, IE users), you can get by with a simpler approach—use the let keyword instead of var for the loop variable:

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

有了这个小小的改变,每个 funArr 元素都是一个闭包绑定,在每次循环迭代中做一个 不同 i 对象.有关 let 的更多信息,请参阅 这篇来自 2015 年的 Mozilla Hacks 帖子.(如果您的目标环境不支持 let,请坚持我之前编写的内容,或者在使用前通过转译器最后运行它.

With that little change, each funArr element is a closure bound do a different i object on each loop iteration. For more info on let, see this Mozilla Hacks post from 2015. (If you're targeting environments that don't support let, stick with what I wrote earlier, or run this last through a transpiler before using.

这篇关于Javascript:在 For 循环中创建函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆