ES6 已经出现很长时间了,可是做为一个初学者,仍然要仔细深刻的理解这些点,接下来我会写一个 ES6 语法系列,深刻讲解 ES6 语法产生的背景与用法,但愿能给你们带来帮助。javascript
你们都清楚,在 let 声明方式出现以前,咱们声明一个变量只能经过 var 来定义。html
var a = 1;
var b = 'zhangsan';
var c = {name: 1, age: 2};
var d = function(){}
var e = [];
复制代码
一切都很正常,直到有一天,咱们写出了这样的代码:java
for(var i = 0; i < 10; i++){
setTimeout(function(){
console.log(i);
});
}
复制代码
咱们指望使用这种代码,获得以下结果:闭包
0
1
2
3
4
5
6
7
8
9
复制代码
但事实却很打脸,获得的结果以下:函数
这和咱们的指望结果不太同样,为何会获得这样的结果呢? 在此能够说明一下,虽然有些跑题。ui
缘由有二:spa
一个缘由是: var 定义的变量不受块级做用域的限制。code
另外一个缘由是:JavaScript 引擎的事件循环机制在起做用。for循环的同步任务执行完毕以后,才会将从事件队列中取出回调函数,放到调用栈中执行:即setTimeout
的回调函数。因此当同步任务执行完以后, i 的值已经变为了 10,此时,10 个定时器的回调开始执行,打印出 10 个 10。cdn
那么,聪明的同窗开始想办法了,利用 JS 中的闭包特性,实现指望的结果:htm
for(var i = 0; i < 10; i++){
(function(t){
setTimeout(function(){
console.log(t);
});
})(i);
}
复制代码
能够看到,代码不易理解,书写也很麻烦。
因而 ES6 中新出现了 let 声明方式, 经过 let 声明的变量有了块级做用域
的限制。 举个例子,先从 var 声明开始:
{
var a = 1;
}
console.log(a);
复制代码
因为 var 没有块级做用域的约束,因此咱们在块级做用域之外访问 a 变量的话,仍然是可以访问到的。所以,上面的定时器例子会打印出 10 个 10。
接下来,咱们将 var 改成 let 进行声明:
{
let a = 1;
}
console.log(a);
复制代码
你们能够猜想一下输出结果是什么?
事实上会报错的:
缘由在于,按照 let 的声明特色, let 定义的变量只能在声明时所在的做用域中访问到,因此 a 被限制在了块级做用域中,在块级做用域外访问 a 的话,因为外层做用域并未定义 a 变量,因此会报上述错误。
既然 let 有了块级做用域的约束,咱们就能够用 let 来改写上面的定时器例子:
for(let i = 0; i < 10; i++){
setTimeout(function(){
console.log(i);
});
}
复制代码
之前咱们用 var 声明变量的时候,能够重复进行同名变量的声明,好比
var a = 1;
var a = 2;
var a = 3;
console.log(a);
复制代码
以上代码,没有报错,而且 a 的值获得了篡改,以最后一次赋值为准。
你们可能以为没有问题。
咱们再举一个例子:
假设 A、B、C 三个同窗须要共同完成一个页面功能。
A同窗写了一个 JS 文件 A.js,A同窗再这个文件中定义了一个name变量,赋值为章三
,他想在页面上将这个名字打印出来。
var name = '章三';
复制代码
B同窗写了另外一个 JS 文件 B.js,也定义了一个变量,也叫 name,赋值为 '李四',他也想在页面上将这个名字打印出来。
var name = '李四';
复制代码
A 同窗告诉 C 同窗,取出 name 属性,打印出来就能够了。
B 同窗告诉 C 同窗,取出 name 属性,打印出来就能够了。
惋惜 C 同窗不是一个细心的同窗,他没有意识到两个变量重名了,因而他写了一个 html 文件,引入了 A.js 和 B.js,而后将 name 属性打印出来。
<script src="./A.js"></script>
<script src="./B.js"></script>
<body>
<div id="name"> </div>
<script> document.querySelector('#name').innerHTML = name; </script>
</body>
复制代码
而后 C 同窗将页面发给 A 同窗和 B 同窗,让他们看一下结果对不对。
结果 A 同窗一看,发现打印出来的名字不是章三
,而是 李四
,他就怒气冲冲地去质问 C 同窗,C同窗说,我就是按照你告诉个人方式去打印的呀。
故事进行到这里,矛盾出现了:
同一个做用域下定义多个重名变量,JavaScript 引擎不会报错,可是会为程序的正确性带来隐患。
幸运的是,let 的出现很好地解决了这个问题:
同一个做用域下,let 声明的变量不能和已经声明的变量重名,不然引擎会报错。
let a = 1;
let a = 2;
复制代码
或者
var a = 1;
let a = 2;
复制代码
因此,let 为咱们带来了另外一个好处,防止咱们定义重名变量。
仍然以一段代码为例:
console.log(a);
var a = 1;
复制代码
你们猜想一下,输出结果是什么?
程序运行不会报错,可是输出结果不是咱们指望的。
输出结果是 undefined。
因此,这会带来一个问题,咱们在声明一个变量以前,万一使用了这个变量,就会获得意料以外的结果,进而形成程序运行错误,若是能有一种机制可以强制咱们在使用变量以前,必须先声明该变量就行了。
这就是 let 的第三个特色:使用一个 let 声明的变量以前,必须先声明。
console.log(a);
let a = 1;
复制代码
如上代码,a 变量的声明放在了使用以后,咱们看下运行结果:
编译器给出了报错提示,这促使咱们在早期就能发现问题。
以上就是 ES6 的 let 使用总结,虽然是一个很小的点,可是咱们也要认清它出现的背景,为了解决什么问题而生。
以后,会为你们带来 ES6 其余语法的剖析,敬请期待~~~