闭包典型-for循环
一、闭包的概念
- 闭包就是有权访问另一个函数作用域中变量的函数,闭包的主要存在形式就是在一个函数内部创建另一个函数,通过另一个函数访问这个函数的局部变量
二、for循环按顺序顺出
-
for (var i = 0; i < 5; i++) { setTimeout(() => { console.log(i); }, 1000); }
执行结果:输出五个5
解析:for循环的时候,你并没有执行这个函数,你这个函数是过一秒才执行的,当执行这个函数的时候,
它发现它自己没有这个变量i,于是向它的作用域链中查找这个变量i,因为这个时候已经for循环完了,
所以储存在作用域链里面的i的值就是5,最后就打印出来5了。
- 如何按顺序打印索引呢?
- 使用let
for (let i = 0; i < 5; i++) { setTimeout(() => { console.log(i); }, 1000); } //等价于 // for (let i = 0; i < 5; i++) { // let index = i; // setTimeout(() => { // console.log(index); // }, 1000); // }
- 使用let
执行结果:
解析:
利用 let 变量的特性 — 在每一次 for 循环的过程中,let 声明的变量会在当前的块级作用域里面
(for 循环的 body 体,也即两个花括号之间的内容区域)创建一个文法环境(Lexical Environment),
该环境里面包括了当前 for 循环过程中的 i
-
- 自执行函数
// for (var i = 0; i < 5; i++) { // (function (i) { // setTimeout(() => { // console.log(i); // }, 1000); // })(i); // } //等价于 因为你在循环变量i的时候已经执行了函数,自然变量i是什么就打印出来什么 for (var i = 0; i < 5; i++) { function temp(i) { setTimeout(() => { console.log(i); }, 1000); } temp(i); }
执行结果:
- 自执行函数
解析:
利用函数自执行的方式,把当前 for 循环过程中的 i 传递进去,变量i保存到这个自执行函数构建出的块级作用域中,IIFE 其实并不属于闭包的范畴
-
- 使用定时器的第三个参数
for (var i = 0; i < 5; i++) { setTimeout( (i) => { console.log(i); }, 1000, i ); }
执行结果:
- 使用定时器的第三个参数
解析:
利用 setTimeout 函数的第三个参数,会作为回调函数的第一个参数传入
三、for循环中每隔一秒打印一次 0 1 2 3 4 5
- es5的方法:1000*i是重点
for (var i = 0; i < 5; i++) { (function (i) { setTimeout(() => { console.log(i); }, 1000 * i); })(i); } setTimeout(function () { console.log(i); }, 1000 * i);
- es6的方法
let tasks = []; function sleep(i) { return new Promise((resolve, reject) => { setTimeout(() => { console.log(i); resolve(); }, 1000 * i); }); } for (let i = 0; i < 5; i++) { tasks.push(sleep(i)); } Promise.all(tasks).then(() => { setTimeout(() => { console.log(i); }, 1000); });
- es7的方法:
function sleep(time) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(); }, time); }); } (async function () { for (var i = 0; i < 5; i++) { await sleep(1000); console.log(i); } setTimeout(() => { console.log(i); }, 1000); })();
北栀女孩儿