在js高程中,做者强调说js没有块级做用域。
然而,这种状况在es6中发生了改变,es6经过在代码块中使用let, const引入了块级做用域的特性。
下面是对此特性的介绍。es6
首先,在es5中,只有两种做用域,函数做用域和全局做用域。 全部的变量和函数声明都存在于这两种做用域中。面试
js在执行时,会首先将函数定义和变量声明提高到做用域的顶部,而初始化的代码留在原处,这就是变量提高。 这是js语言与其余语言不一样的地方。闭包
在块级做用域内部使用let, const声明的变量,在块做用域外部是不可见的。函数
var count = 30; let count = 20; //这里不管顺序,不管let或const,都会报错。 //只有这种才不会报错 var count = 30; var count = 20; //第二个var被忽略,count等于20
if(condition){ console.log(typeof value);//会报错 let value = 'icode007' }
js有一道经典的面试题,即在页面插入10个a标签,点击每一个标签时显示相应的序号。或者是:es5
var arr = []; for(var i =0; i<10; i++){ arr.push(function(){console.log(i)}); } arr[5]();
这道题常常用来讲明变量的做用域和闭包的相关问题。由于全部的函数引用的都是同一个i,因此都显示10.
正确的代码是使用当即执行函数,利用闭包特性:指针
var arr = []; for(var i=0; i<10; i++){ (function(i){ arr.push(function(){console.log(i);}); })(i); } arr[5]();
经过闭包,每一个函数调用的其实是其独有的i。code
然而,在es6,有个更好的方案,使用let。只需将第一段代码i声明中var换成let便可。对象
在for循环中,每次迭代let都会建立一个新的同名变量,并进行初始化,至关于上面使用当即执行函数的行为。在for-in循环和for-of循环中,一样如此。作用域
const声明的变量是不可变的,其实质是变量所引用的指针不能发生变化,但因为js动态语言的本质,当const声明一个对象时,对对象的改变是容许的。好比:it
const obj = {name: 'icode'}; obj.name ='thoms'; //不会发生错误 obj = {name: "thoms"} //发生错误
在for-in和for-of迭代中使用const与使用let的行为相同,前提是再也不代码块中改变它的值,在for循环中,因为i++会改变变量的值,因此会报错。
在以前全局中使用var定义的变量会成为window对象的一个属性,而在全局中使用let, const定义的变量不会成为window对象的属性。
推荐的最佳实践是尽可能使用let而不是使用var去定义变量,这能让咱们代码更加的规范。
更加推荐的作法是通常使用const定义变量,只有在预期变量会发生改动时才使用let来定义。由于大部分变量定义后是无需发生变化的。这种方式能减小代码出错的概率。