第二节:ES6新增了let关键字

原文来自:http://mp.weixin.qq.com/s/4oXvIjtpcSS0EMHF44UBkQ
ES6 给开发者带来很多令人激动的特性,其中let关键字就是其中之一。

    那么,let关键字是什么东西?

let 的用途
我们回想一下,我们平时在写代码的时候,用var来声明一个变量,除此之外,好像也没用其他的关键字了,不管我们声明的是字符串类型、数组类型还是数字类型等,都用一个var 搞掂(因为JavaScript拥有动态类型),很方便。但现在,ES6告诉你,除了var,不妨试试用let来声明变量试试看。

    咦,这么说,let关键字是用了声明变量的咯?是的,let的用途就是用来声明变量的。
    那么,let关键字是什么东西?
    好端端的用var声明就可以了,为什么要用新的let关键字来声明啊?难道用var有什么不足的地方吗?是的,还真有。

用 var 的不足之处

不足一

来,我们看一段简短的代码:

var arr = [ ];
for(var i=0; i<10; i++){

arr [i] = function(){

     alert(i)

}

}

arr 8; //结果:10

    看代码,不难猜测代码的意图是想给数组a的元素赋值,每一个元素是一个函数,运行后弹出相对应的数字,比如:运行arr[8]();想alert出一个数字8,运行arr[1](); 想alert出一个数字1,依次类推。但是结果并不是我们预想的那样。运行后实际弹出的是10;不管你运行的是arr[8]还是arr[5],或者是数组内的其他元素,都是alert出一个数字:10。但这并不是我们想要的(不要说你故意这么写的,就是想弹出10就好了),为什么是10呢(往下读,有解释)?至少目前我们可以知道了这是var不足的地方。

    那么let能解决这个问题吗?ES6说:能啊,不信你试试看!

用let替换var后,我们再看看:

var arr = [ ];

for(let i=0; i<10; i++){

arr[i] = function(){

     alert(i)

}

}

arr8; //结果:8

   对比一下两段代码,唯一的不同之处就是循环的时候初始化变量 i 是使用let,而不是用var,运行arr[8]()后确实弹出了数字8;如果运行的是arr[3](),就会弹出数字3;这才是我们的本意啊,总算实现了,感谢上帝,感谢ES6,感谢let关键字!

    为什么用let就可以,用var就跑偏了呢?这是因为let声明的变量仅仅在自己的块级作用域起作用,出了这个块级作用域就不起作用。就好比,小明在国内考的“高级程序员”证,去到国外应聘,别人就不承认你的文凭了,小明只能乖乖待在国内持证上岗。而let声明的变量也一样,出不了自己的块级作用域。

    那么,什么是块级作用域,怎么才算一个块级作用域?

    任何一对花括号(这玩意:{ })中的语句都属于一个块,在花括号里面用let定义的所有变量在花括号外都是不可见的,我们称之为块级作用域。

    怪不得小明的证件去到美国没法使用了,人家认为它的证件“不可见“,就是没这回事,不承认你的证。回到代码中,for循环含有有{ },也就是含有了块级作用域,每个变量 i 都只是在自己的作用域起作用,例如:第10次循环中的 i 的值不会影响到到第9次循环。

    如果用var声明的变量,就不是这种情况了,i 的值会影响到各个块里面的 i,等循环完后 i 等于10,所有块的i都变成了10了。这就是为什么第一段代码运行后会弹出数字10了,这并不是我们想要的。

    就好比小明陆陆续续去了10个国家玩,每到一个国家都给自己弄了一个不同的身份,但是小明被告知以后只能用在第10个国家取得的那个身份,那么之前9个国家认识小明的朋友都会不认识他的,小明当场就懵逼了。

不足二
用var 声明变量的时候会出现“变量提升“的现象。
“ 变量提升“是什么鬼?新概念第一次听?前端君快来解释一下!

再看一段简短的代码:

var a = 1;

(function(){

alert(a);

var a = 2;

})();//结果:undefined

    初学者可能认为:代码一开始已经定义了变量a,值为1,相当于全局变量,代码运行的时候会先弹出这个全局变量a的值:1;然后再重新给a赋值为2;可偏偏又事与愿违,心好累啊,它会告诉你结果是undefined; undefined就是未定义啊,为什么会是未定义呢?

    原因就在于我们在代码块(函数内)里面还声明并定义了一个变量a,导致变量提升了,实际的代码执行顺序是这样的,仔细看完你就知道什么叫变量提升了。

var a = 1;

(function(){

var a;

alert(a);

a = 2;

})();

    对比一下两段简短的代码:var a = 2; 这句代码被拆分成两部分:声明var a ; 和 定义a = 2;而声明部分被提升(看到了吗?提升两个字出现了)到了代码块的前面,运行的时候自己挪到前面了,这就是“变量提升“,结果就是:先执行声明,接着就执行alert(a);变量a只是声明还没定义,就弹出了undefined了。

    所以,归根结底就是“变量提升“在作怪。这就是var的又一大不足之处。那么,用let关键字在代码块就不会被提升了吗?是的,不提升了。             

如果你用let这样重写刚刚那段代码的话:

var a = 1;

(function(){

alert(a);

let a = 2;

})(); // 结果:报错a未定义

    用let关键字来定义a;这样a在代码块内就不会提升了。那为什么又报错了呢,因为用let声明的变量,在其块级作用域内是封闭的,是不会受到外面的全局变量a影响的,并且要先声明再使用,所以a的值即不是1(因为不受外面的影响),也不是undefined(因为先声明后使用),更不是2,未声明定义就使用,只有报错啦。

    用let关键字也算是提醒我们,平时记得先声明定义再使用的好习惯。

    光是var的不足就讲了这么长的篇幅,希望没把你们闷到,我尽量用一些生活的例子来打比方,如果你能能坚持看到这里很不错了,还有一点,再坚持一下。

这么说,let确实能弥补一些var的不足之处。那么使用let的时候还有什么要注意的吗?有的!

注意1:同一个块级作用域内,不允许重复声明同一个变量。

错误示范一:

{

var a =1;

let a =2; //报错,因为a已经用var声明过

}

错误示范二:

{

let a =1;

let a= 2; //还是报错,a已经用let声明过。

}

注意2:函数内不能用let重新声明函数的参数

错误示范:

function say(word){

let word = 'hello Jack';  //报错:用let重新声明word参数

alert(word)

}

say('hello Lili');

say()函数内用let重新声明了word这个参数,会报错的,千万别这么干。

本节总结

总结:用let声明变量只在块级作用域起作用,适合在for循环使用,也不会出现变量提升现象。同一个代码块内,不可重复声明的相同变量,不可重复声明函数内的参数。

你可能感兴趣的:(第二节:ES6新增了let关键字)