闭包和let块级作用域
程序员文章站
2022-12-23 15:54:20
还是先从一个题目开始: 写一个隔1s输出数组的一项的函数。 如果可以用ES6语法,则可以这么写: 但是如果把这里的 改成 ,则输出就会变成一连串的 。 有同学很快想到了这是闭包啊,因为 把函数加入到 中,所以等到setTimeout的函数体执行时, 已经走完了 循环,变成了 。`arr[arr.le ......
还是先从一个题目开始:
写一个隔1s输出数组的一项的函数。
如果可以用es6语法,则可以这么写:
function print (arr) { for (let i = 0; i < arr.length; i++) { settimeout(() => { console.log(arr[i]) }, 1000 * i); } }
但是如果把这里的let
改成var
,则输出就会变成一连串的undefined
。
有同学很快想到了这是闭包啊,因为settimeout
把函数加入到microqueue
中,所以等到settimeout的函数体执行时,i
已经走完了for
循环,变成了arr.length
。arr[arr.length]
显然是undefined。
简单修改一下,变成es5的语法。
function print (arr) { for (var i = 0; i < arr.length; i++) { (function (index) { settimeout(() => { console.log(arr[index]) }, 1000 * index); })(i); } }
其实就是利用闭包是向父级作用域寻找值的特性,给i
包装一层作用域,把i
存起来。
闭包概念还请翻看。
到这里闭包的理解应该差不多了,而今天的关键点在于——
let做了什么?
阮一峰老师的《ecmascript 6》入门里给出[定义](:
es6 新增了
let
命令,用来声明变量。它的用法类似于var
,但是所声明的变量,只在let
命令所在的代码块内有效。
他提到了let的几个特性:
只存在于块级作用域中
不存在变量提升
暂时性死区
不允许重复声明
这里我不再赘述,大家可以仔细阅读一下阮一峰老师的书。
我更感兴趣的是,在es5的语法中,如何模拟let
这种块级作用域的效果。这个时候,应该让babel
出场了。
打开这个链接:可以看到转换后的代码。
"use strict"; function print(arr) { var _loop = function _loop(i) { settimeout(function () { console.log(arr[i]); }, 1000 * i); }; for (var i = 0; i < arr.length; i++) { _loop(i); } }
其实可以对比发现,babel
转换后的代码和我们上面写的es5实现其实是一样的。
大概就是通过对let
绑定的块级作用域加一个函数,把let
声明的参数,通过函数传入,达到块级作用域的效果。
大家可以在babel
试一下let
的其他特性,转移出的es5语法并不能实现有的特性,比如暂时性死区。
完,感谢阅读。