本帖最后由 dkxhy 于 2017-12-8 15:40 编辑
ES6已经出来很久了,应用也越来越广泛,而且面试中也越来越多的问道有关es6的东西。今天,我们来学习一下es6总let的实现原理。在学习之前,我们先看一下let的特点:
1, 块级作用域
2,无变量提升
3,暂时性死区
4,不允许重复声明
这篇帖子主要看一下块级作用域的原理。
一,块级作用域
先来看一个非常经典的例子
----例1----
[JavaScript] 纯文本查看 复制代码 var a=[];
for(var i=0;i<10;i++){
a[i]=function(){
console.log(i);
};
}
[/i] a[6](); //10 这是最常见的写法,我们来看一下代码的执行过程。
var i=0;//此时的var定义的变量是全局的。
a[0]=function(){
console.log(i);//这里之所以i为i而不是0;是因为我们只是定义了该函数,未被调用,所以没有进入该函数执行环境,i当然不会沿着作用域链向上搜索找到i的值。
}
var i=1;//第二次循环,因为是全局的, i=1;覆盖了前面的 i=0;即现在i为1;
a[1]=function(){
console.log(i);//解释同a[0]函数。
}var i=2;// 第三次循环,这时 i=2,在全局作用域中,所以覆盖了前面的i=1;
a[2]=function(){
console.log(i);
} ......第四次循环 此时i=3 这个以及下面的i不断的覆盖前面的i,因为都在全局作用域中
......
......第九次循环 此时i=8
var i=9;
a[9]=function(){
console.log(i);
}
var i=10;// 这时i为10,因为不满足循环条件,所以停止循环。
紧接着在全局环境中继续向下执行。
a[6]();//这时调用a[6]函数,所以这时随即进入a[6]函数的执行环境,即a[6]=function(){console.log(i)};执行函数中的代码 console.log(i); 因为在函数执行环境中不存在变量i,所以此时会沿着作用域链向上寻找,即进入了全局作用域中寻找变量i,而全局作用域中i=10覆盖了前面所有的i值,所以说这时i为10,那么a[6]的值就是10了。----例2----[JavaScript] 纯文本查看 复制代码 var a=[];
for(let i=0;i<10;i++){
[i] a=function(){
console.log(i);
};
}
a[6](); //6 { //进入第一次循环
let i=0; //注意:因为使用let使得for循环为块级作用域,此次let i=0在这个块级作用域中,而不是在全局环境中。
a[0]=function(){
console.log(i);
}; //注意:由于循环时,let声明i,所以整个块是块级作用域,那么a[0]这个函数就成了一个闭包。
}// 声明: 我这里用{}来模拟块级作用域的存在。
{ //进入第二次循环
let i=1; //注意:因为let i=1; 和 上面的let i=0;出在不同的作用域中,所以两者不会相互影响。
a[1]=function(){
console.log(i);
}; //同样,这个a也是一个闭包
}
......进入第三次循环,此时其中let i=2;
......
......进入第九次循环,此时其中let i=8;
{//进入第十次循环
let i=9;
a=function(){
console.log(i);
};//同样,这个a也是一个闭包
}
a[6]();//调用a[6]()函数,这时执行环境随即进入下面这个代码块中的执行环境:funcion(){console.log(i)};
{
let i=6;
a[6]=function(){
console.log(i);
}; //同样,这个a也是一个闭包
} 每次for循环都会创建一个{}块级作用域,相当于在内存中又重新开了一块区域去存储变量和函数,不会互相影响。执行a[6]时,首先在当前函数内部找这个变量,没有的话会沿着作用域链向上找,
当前作用域内有i= 6,就直接使用。因此,打印结果为6.
相信大家仔细看完上面的函数执行的过程,对let var 块级作用域 闭包就有一个很好的理解了。我认为重要的是对于函数执行过程的理解!
|