详解ES6之用let声明变量以及let loop机制


Posted in Javascript onJuly 15, 2017

在上一篇对js闭包的理解那篇文章中,我提到过ES6之前,JavaScript这门语言没有块级作用域,但是在ES6中,加入了let命令,用let声明的变量仅仅可以在其所在的块级作用域中使用。

相比用var声明,let声明的特点

1.let声明的变量仅在该变量所在的作用域有效

for(let i=0;i<5;i++){} console.log(i); //报错
for(var i=0;i<5;i++){} console.log(i); //i=5;

2.不存在变量提升

先解释下变量提升:变量提升就是变量声明语句都会被提到所在作用域开始处,就是经过变量提升后,代码的实际执行顺序会与你所写的顺序不同。

console.log(i);
var i=2;

因为变量提升,所以上述代码不会报错,只会输出undefined。

但是要注意:变量提升只是提升声明语句,而不提升赋值语句

所以上述语句经过提升之后,实际的代码执行顺序是

var i;
console.log(i);
i=2;

再来看道经典试题

var name = 'World!'; 
(function () { 
if (typeof name === 'undefined') { 
  var name = 'Jack'; 
  console.log('Goodbye ' + name); 
}else{ 
  console.log('Hello ' + name); 
} 
})();

请问最终console的结果是什么?

如果对变量提升一无所知,会很容易的得出hello world的结果。

我对变量提升略知一二,得出的结果是hello Jack.

但是正确结果是Goodbye Jack. 做错的原因就是我没有注意到变量提升仅仅是声明提升。

3.不可以在同一作用域内重复声明

function temp(){
   let a;
   let b; 
} //报错

4.暂时性死区

var tmp="123"; 
if(true){ 
 tmp="abc";
 let tmp;
}

定义(出自ES6标准入门一书):在代码块内,使用let变量声明之前,该变量是不可以用的。这在语法上称为暂时性死区。

但是如果去掉上述let tmp;这句,代码是不会错的,只是这时的tmp即外部的全局变量,但是你如果要声明一个与外部变量同名的局部变量,那么你就要放在这个同名变量使用之前,否则就会报错。

说一说(let i=0;i<5;i++)的运行机制

不好意思,我们还得拿闭包来说事。

var a=[]; 
for(var i=0;i<5;i++){
  a[i]=function(){
    console.log(i);
  }
}

然后,结果i并非我们想象得那样,按照0,1,2...的顺序打印,而都是打印5,在上一篇文章理解js闭包中,我们已经知道如何用闭包解决这个问题。但是呢,这还有一种更简单的解法,如下

for(let i=0;i<5;i++){
   a[i]=function(){
     console.log(i);
   }
}

对,就是这么简单,用一个let代替var,就搞定了。但是为什么呢?说实话,闭包我能想得通,但是用let真心想不通为什么可以解决这个问题。问过一些人,但是他们只是很糊弄得说,let是块级作用域。我觉得他们压根就没有搞懂,我觉得这里绝对有蹊跷,仅仅凭let是块级作用域并不能解释的通,一定有其他机制。

我的疑惑:就算let是块级作用域,可是在函数里,我们没有定义新的i,所以你访问i,其实都在访问父级作用域,对 let i=0;使得i只能在for循环的{}内使用,但是当你调用ai的时候,不管i是多少,它们都应该是访问的是同一个i,怎么会出现0,1,2,3,4呢?
百度一下,果然不出我所料,阮一峰大神给出的解释是,对每一次循环,都是产生不同的i,所以5次循环,产生了5个块级作用域,而不同的块级作用域间实现i++是通过js引擎记住上一个i值实现的。这样一来,ai调用时,就会访问到与自己对应的i,而不是同一个i.

所以,let可以得到闭包的效果是因为let具有块级作用域,与let loop特殊的机制。

起初,我对这个结果不太相信,因为和直觉不太相符,感觉5次循环,产生5个i,和自己以前的认知不大相同啊。然后我有有了新的发现

第一个发现:

for(let i=0;i<5;i++){
   let i="abc";
   console.log(i);
}

我吃惊的是竟然没有报错!说好的let不可以重复声明呢?这充分证明了let i=0;与let i="abc"不在同一个作用域。

第二个发现:可以通过babel将ES6代码转为ES5,看看上述代码是如何实现的?

详解ES6之用let声明变量以及let loop机制

先创建一个loop函数,最终在循环的时候调用loop函数并将i作为参数传入,这样便会形成5个不同的副本。这也证明了用let代替闭包,关键是形成了5个不同的块级作用域。

最后,ES6只是一种规范,比如说let的规范,但实现该规范的是JS引擎,如babel对上述代码的转换便体现出了babel对let loop的实现。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
如何快速的呈现我们的网页的技巧整理
Jul 01 Javascript
js动态创建标签示例代码
Jun 09 Javascript
jQuery之Deferred对象详解
Sep 04 Javascript
原生Js实现简易烟花爆炸效果的方法
Mar 20 Javascript
jquery无限级联下拉菜单简单实例演示
Nov 23 Javascript
学习JavaScript设计模式(策略模式)
Nov 26 Javascript
原生js和jquery分别实现横向导航菜单效果
May 13 Javascript
jQuery封装的屏幕居中提示信息代码
Jun 08 Javascript
JS简单获取客户端IP地址的方法【调用搜狐接口】
Sep 05 Javascript
canvas实现动态小球重叠效果
Feb 06 Javascript
js 博客内容进度插件详解
Feb 19 Javascript
解决vue一个页面中复用同一个echarts组件的问题
Jul 19 Javascript
vue增删改查的简单操作
Jul 15 #Javascript
JavaScript实现跟随滚动缓冲运动广告框
Jul 15 #Javascript
Javascript实现基本运算器
Jul 15 #Javascript
基于AngularJS的拖拽文件上传的实例代码
Jul 15 #Javascript
Javascript实现时间倒计时效果
Jul 15 #Javascript
JavaScript实现的可变动态数字键盘控件方式实例代码
Jul 15 #Javascript
JavaScript实现时间表动态效果
Jul 15 #Javascript
You might like
Zend Studio (eclipse)使用速度优化方法
2011/03/23 PHP
火狐4、谷歌12不支持Jquery Validator的解决方法分享
2011/06/20 Javascript
jQuery 中使用JSON的实现代码
2011/12/01 Javascript
JS 实现列表与多选框选择附预览动画
2014/10/29 Javascript
javascript判断移动端访问设备并解析对应CSS的方法
2015/02/05 Javascript
jQuery拖拽排序插件制作拖拽排序效果(附源码下载)
2016/02/23 Javascript
详解Angular.js的$q.defer()服务异步处理
2016/11/06 Javascript
解决前端跨域问题方案汇总
2016/11/20 Javascript
JS实现直接运行html代码的方法
2017/03/13 Javascript
Vuex之理解Getters的用法实例
2017/04/19 Javascript
js 简易版滚动条实例(适用于移动端H5开发)
2017/06/26 Javascript
es6+angular1.X+webpack 实现按路由功能打包项目的示例
2017/08/16 Javascript
详解Chai.js断言库API中文文档
2018/01/31 Javascript
详解vue-cli+element-ui树形表格(多级表格折腾小计)
2019/04/17 Javascript
详解基于mpvue微信小程序下载远程图片到本地解决思路
2019/05/16 Javascript
[06:33]DOTA2亚洲邀请赛小组赛第二日 TOP10精彩集锦
2015/01/31 DOTA
[01:17]辉夜杯战队访谈宣传片—EHOME
2015/12/25 DOTA
[02:29]完美世界高校联赛上海赛区回顾
2015/12/15 DOTA
[00:56]跨越时空加入战场 全新祈求者身心“失落奇艺侍祭”展示
2019/07/20 DOTA
[59:32]Liquid vs Fnatic 2019国际邀请赛淘汰赛败者组BO1 8.20.mp4
2020/07/19 DOTA
python实现在pickling的时候压缩的方法
2014/09/25 Python
python批量设置多个Excel文件页眉页脚的脚本
2018/03/14 Python
详解python中init方法和随机数方法
2019/03/13 Python
python语言基本语句用法总结
2019/06/11 Python
python中selenium操作下拉滚动条的几种方法汇总
2019/07/14 Python
Django 多表关联 存储 使用方法详解 ManyToManyField save
2019/08/09 Python
如何分离django中的媒体、静态文件和网页
2019/11/12 Python
Python(PyS60)实现简单语音整点报时
2019/11/18 Python
Python爬虫抓取指定网页图片代码实例
2020/07/24 Python
python 递归相关知识总结
2021/03/03 Python
道路建设实施方案
2014/03/18 职场文书
学校交通安全责任书
2014/08/25 职场文书
王金山在党的群众路线教育实践活动总结大会上的讲话稿
2014/10/25 职场文书
高三语文复习计划
2015/01/19 职场文书
导游词之海南天涯海角
2019/12/05 职场文书
python生成可执行exe控制Microsip自动填写号码并拨打功能
2021/06/21 Python