首页 > JavaScript > 在每个匿名函数中,绑定到函数外部的同一变量

在每个匿名函数中,绑定到函数外部的同一变量

上一篇 下一篇

var funcs = [];
// let's create 3 functions
for (var i = 0; i < 3; i++) {
  // and store them in funcs
  funcs[i] = function() {
    // each should log its value.
    console.log("My value:", i);
  };
}
for (var j = 0; j < 3; j++) {
  // and now let's run each one to see
  funcs[j]();
}

它输出以下内容:

我的值:3
我的值:3
我的值:3

而我希望它输出:

我的值:0
我的值:1
我的值:2


当运行函数的延迟是由使用事件侦听器引起的时,会出现同样的问题:

var buttons = document.getElementsByTagName("button");
// let's create 3 functions
for (var i = 0; i < buttons.length; i++) {
  // as event listeners
  buttons[i].addEventListener("click", function() {
    // each should log its value.
    console.log("My value:", i);
  });
}
<button>0</button>
<br />
<button>1</button>
<br />
<button>2</button>

…或异步代码,例如使用 Promises:

// Some async wait function
const wait = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms));

for (var i = 0; i < 3; i++) {
  // Log `i` as soon as each promise resolves.
  wait(i * 100).then(() => console.log(i));
}

在和循环中也很明显:for infor of

const arr = [1,2,3];
const fns = [];

for (var i in arr){
  fns.push(() => console.log("index:", i));
}

for (var v of arr){
  fns.push(() => console.log("value:", v));
}

for (const n of arr) {
  var obj = { number: n }; // or new MyLibObject({ ... })
  fns.push(() => console.log("n:", n, "|", "obj:", JSON.stringify(obj)));
}

for(var f of fns){
  f();
}

这个基本问题的解决方案是什么?

分割线

网友回答:

尝试:

var funcs = [];
    
for (var i = 0; i < 3; i++) {
    funcs[i] = (function(index) {
        return function() {
            console.log("My value: " + index);
        };
    }(i));
}

for (var j = 0; j < 3; j++) {
    funcs[j]();
}

编辑 (2014):

我个人认为@Aust最近关于使用的答案是现在做这种事情的最好方法。当您不需要或不想弄乱 ‘s 时,还有 lo-dash/下划线。.bind_.partialbindthisArg

分割线

网友回答:

好吧,问题是 变量 ,在每个匿名函数中,绑定到函数外部的同一变量。i

ES6 解决方案:let

ECMAScript 6 (ES6) 引入了 new 和 关键字,其作用域与基于变量的变量不同。例如,在具有基于 -的索引的循环中,循环的每次迭代都会有一个具有循环作用域的新变量,因此您的代码将按预期工作。有很多资源,但我推荐 2ality 的块范围帖子作为重要的信息来源。letconstvarleti

for (let i = 0; i < 3; i++) {
  funcs[i] = function() {
    console.log("My value: " + i);
  };
}

但是请注意,Edge 9 之前的 IE11-IE14 和 Edge 支持 3,但上述内容是错误的(它们不会每次都创建一个新函数,因此上面的所有函数都会像我们使用时一样记录 14)。边缘 <> 终于做对了。letivar


ES5.1解决方案:适用于每个

随着该函数的相对广泛的可用性(在 2015 年),值得注意的是,在那些主要涉及对值数组进行迭代的情况下,提供了一种干净、自然的方式来为每次迭代获得不同的闭包。也就是说,假设你有某种包含值(DOM 引用、对象等)的数组,并且出现设置特定于每个元素的回调的问题,你可以这样做:Array.prototype.forEach.forEach()

var someArray = [ /* whatever */ ];
// ...
someArray.forEach(function(arrayElement) {
  // ... code code code for this one element
  someAsynchronousFunction(arrayElement, function() {
    arrayElement.doSomething();
  });
});

这个想法是,与循环一起使用的回调函数的每次调用都将是它自己的闭包。传递给该处理程序的参数是特定于迭代的特定步骤的数组元素。如果在异步回调中使用,则不会与在迭代的其他步骤中建立的任何其他回调发生冲突。.forEach

如果你碰巧在jQuery工作,这个函数会给你一个类似的功能。$.each()


经典解决方案:瓶盖

您要做的是将每个函数中的变量绑定到函数外部的单独不变值:

var funcs = [];

function createfunc(i) {
  return function() {
    console.log("My value: " + i);
  };
}

for (var i = 0; i < 3; i++) {
  funcs[i] = createfunc(i);
}

for (var j = 0; j < 3; j++) {
  // and now let's run each one to see
  funcs[j]();
}

由于 JavaScript 中没有块作用域 – 只有函数作用域 – 通过将函数创建包装在新函数中,您可以确保“i”的值保持您的预期。

分割线

网友回答:

另一种尚未提及的方法是使用Function.prototype.bind

var funcs = {};
for (var i = 0; i < 3; i++) {
  funcs[i] = function(x) {
    console.log('My value: ' + x);
  }.bind(this, i);
}
for (var j = 0; j < 3; j++) {
  funcs[j]();
}

更新

正如 @squint 和 @mekdev 所指出的,通过先在循环外部创建函数,然后在循环内绑定结果,可以获得更好的性能。

function log(x) {
  console.log('My value: ' + x);
}

var funcs = [];

for (var i = 0; i < 3; i++) {
  funcs[i] = log.bind(this, i);
}

for (var j = 0; j < 3; j++) {
  funcs[j]();
}

模板简介:该模板名称为【在每个匿名函数中,绑定到函数外部的同一变量】,大小是暂无信息,文档格式为.编程语言,推荐使用Sublime/Dreamweaver/HBuilder打开,作品中的图片,文字等数据均可修改,图片请在作品中选中图片替换即可,文字修改直接点击文字修改即可,您也可以新增或修改作品中的内容,该模板来自用户分享,如有侵权行为请联系网站客服处理。欢迎来懒人模板【JavaScript】栏目查找您需要的精美模板。

相关搜索
  • 下载密码 lanrenmb
  • 下载次数 192次
  • 使用软件 Sublime/Dreamweaver/HBuilder
  • 文件格式 编程语言
  • 文件大小 暂无信息
  • 上传时间 02-22
  • 作者 网友投稿
  • 肖像权 人物画像及字体仅供参考
栏目分类 更多 >
热门推荐 更多 >
微信文章 微信素材 微信图片 单页式简历模板 html5 微信公众平台 企业网站 响应式 微信模板 自适应
您可能会喜欢的其他模板