我们先看一个正常的for循环:
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]();
}
它输出这个:
My value:3
My value:3
My value:3
而我希望它输出:
My value:1
My value:2
My value:3
当函数运行延迟是由于使用事件监听器导致时,也会出现同样的问题:
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 in和for 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(var f of fns){
f();
}
这个基本问题的解决方案是什么?好吧,问题是i每个匿名函数内的变量都绑定到函数外的同一个变量。
ECMAScript 6 (ES6) 引入了范围不同于基于变量的新关键字let和const关键字var。例如,在具有let基于索引的循环中,循环中的每次迭代都会有一个i具有循环范围的新变量,因此您的代码将按预期工作。有很多资源,但我建议将2ality 的块范围帖子作为重要的信息来源。
for (let i = 0; i < 3; i++) {
funcs[i] = function() {
console.log("My value: " + i);
};
}
但是请注意,Edge 14 之前的 IE9-IE11 和 Edge 支持let但会出现上述错误(它们不会i每次都创建一个新的,因此上面的所有函数都会像我们使用 那样记录 3 var)。Edge 14 终于做到了。
随着该Array.prototype.forEach函数的相对广泛的可用性(2015 年),值得注意的是,在主要涉及值数组迭代的情况下,.forEach()提供了一种干净、自然的方法来为每次迭代获得不同的闭包。也就是说,假设您有某种包含值(dom 引用、对象等)的数组,并且出现设置特定于每个元素的回调的问题,您可以这样做:
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”的值保持如您所愿。
闭包(closure)是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠...
使用闭包的方式实现一个累加函数 addNum,参数为 number 类型,每次返回的结果 = 上一次计算的值 + 传入的值
JavaScript 变量可以是局部变量或全局变量。私有变量可以用到闭包。闭包就是将函数内部和函数外部连接起来的一座桥梁。函数的闭包使用场景:比如我们想要一个函数来执行计数功能。
for循环中let 和var的区别,setTimeout(func,time)函数运行机制,一个需求,一个数组array[1,2,3,4,5],循环打印,间隔1秒
这篇文章主要介绍了JavaScript的闭包机制,针对内嵌函数的变量访问等问题分析了JS的闭包,写的十分的全面细致,具有一定的参考价值,JavaScript 变量可以是局部变量或全局变量。 私有变量可以用到闭包。
变量作用域:一个变量的作用域是程序源代码中定义这个变量的区域,在函数内声明的变量是局部变量,它只在该函数及其嵌套作用域里可见(js 函数可嵌套定义);
闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式就是在一个函数内部创建另一个函数。来看下面的示例:
使用闭包能够让局部变量模拟全局变量一样,但是它只能被特定函数使用。我们都知道:1.全局变量可能会造成命名冲突,使用闭包不用担心这个问题,因为它是私有化,加强了封装性,这样保护变量的安全
在学习闭包之前,你必须清楚知道JS中变量的作用域。JS中变量的作用域无非就全局变量和局部变量,两者之间的关系是函数内部可以直接访问全局变量,但是函数外部是无法读取函数内部的局部变量的
JavaScript的运行机制:(1)所有同步任务都在主线程上执行,形成一个执行栈。(2)主线程之外,还有一个“任务队列”,只要异步任务有了运行结果,就在“任务队列”之中放置一个事件。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!