欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

闭包和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.lengtharr[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的几个特性:

  1. 只存在于块级作用域中

  2. 不存在变量提升

  3. 暂时性死区

  4. 不允许重复声明

这里我不再赘述,大家可以仔细阅读一下阮一峰老师的书。

我更感兴趣的是,在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语法并不能实现有的特性,比如暂时性死区。

完,感谢阅读。