在说到let的实现方式之前,先看以下为什么会有let
- let使用的较多的情况一般是循环事件中的闭包,例如:
`use strict`
var a = []
for(var i = 0;i<5;i++){
a[i] = function(){
console.log(i)
}
}
for (var k of a){
k();
}
这是一道较为简单的题目,稍微懂点JS基础的都知道,这里
console.log
打印出来的是 5 个 5
- 那么要使打印出来的是我们想要的i 呢?如下:
var a = []
for(let i = 0;i<5;i++){
a[i] = function(){
console.log(i)
}
}
for (var k of a){
k();
}
使用let可以很轻松的达到这个效果
- 那为什么let可以很轻松的达到呢,如果不使用let那可以用什么别的方法吗?如下:
`use strict`
var a = []
for(var i = 0;i<5;i++){
_loop(i)
}
function _loop(i){
a[i] = function(){
console.log(i)
}
}
for (var k of a){
k();
}
这是使用babel将上面let方法polyfill的版本,用以支持不支持ES6语法的浏览器。可以发现,是使用了一个函数将i的值存储下来达到块级作用域的目的。这样临时的变量i就得以保存下来。以下是几钟达到let效果的polyfill版本:
- 使用 try catch方法
`use strict`
var a = []
for(var i = 0;i<5;i++){
try{
throw i
}catch (e){
a[e] = function(){
console.log(e)
}
}
}
for (var k of a){
k();
}
- 使用自执行函数的方法
`use strict`
var a = []
for(var i = 0;i<5;i++){
(function(i){
a[i] = function(){
console.log(i);
}
})(i)
}
for (var k of a){
k();
}
- 使用map函数
`use strict`
var a = []
for(var i = 0;i<5;i++){
[i].map((value)=>{
a[value] = function(){
console.log(value)
}
})
}
for (var k of a){
k();
}
可以发现,在这些方法里,除了try catch以外都是使用函数的作用域来保存i的值
- 以上的介绍都是在循环中使用的实例,那么在非循环中使用又是怎样的实现方法呢?我们来看一个经典的面试题:
var name = 'World!';
(function () {
if (typeof name === 'undefined') {
var name = 'Jack';
console.log('Goodbye ' + name);
}else{
console.log('Hello ' + name);
}
})()
答案是Goodbye Jack。首先JS引擎拿到这段代码会先进行变量提升,实际上的顺序应该是这样的
`use strict`
var name;
name = 'World!';
(function () {
var name
if (typeof name === 'undefined') {
name = 'Jack';
console.log('Goodbye ' + name);
}else{
console.log('Hello ' + name);
}
})();
外面的name实际上没有什么作用,主要是if里面的这个name。在某些编程语言里面,if实际上也是一个块级作用域,在块级作用域里面声明的变量,外面是不可以使用的。但是在JS里面,除了函数具备这个功能外再没有块级作用域了。所以在if里面声明的name会被提升到函数最顶部先行执行,然后判断name是不是undefined类型,因为没有赋值所以答案是true。所以
name = Jack
所以打印出Goodbye Jack
。
那如果题目换成下面这样又是什么结果呢
`use strict` var name = 'World!'; (function () { if (typeof name === 'undefined') { let name = 'Jack'; console.log('Goodbye ' + name); }else{ console.log('Hello ' + name); } })()
因为使用的是let声明,没有变量提升。所以if判断里的name引用的是全局变量name,所以答案是Hello World
简单的polyfill版本
`use strict` var name = 'World!'; (function () { if (typeof name === 'undefined') { (function(){ var name = 'Jack'; console.log('Goodbye ' + name); })() }else{ console.log('Hello ' + name); } })()
可以看到,let的出现简化了大量的JS操作。特有的作用域弥补的JS块级作用域的短板。针对let的polyfill也多是使用函数的作用域来完成,由此可见函数对于JS的重要性。