块级作用域
ES5是不存在块级作用域的,因为不存在块级作用域的关系就会产生很多问题,例如:
var tempArr = []
for (var i = 0; i < 10; i++) {
tempArr[i] = function () {
return i }}
console.log(tempArr[0]());复制代码
因为var存在全局声明的原因所以造成了上述错误。
ECMAScript 6 引入了块级作用域。
将上诉例子var换成let:
var tempArr = []
for (let i = 0; i < 10; i++) {
tempArr[i] = function () {
return i }}
console.log(tempArr[0]());复制代码
let 和 const
let跟const都是声明用作在块级作用域里的参数,let跟const只能在其声明的块作用域中使用。
let跟const的特性:
一.不会被提升
console.log(a);// undefineconsole.log(b); //b is not defined
console.log(c); //c is not defined
var a = 'test'
let b = 'test'
const c = 'test'复制代码
JavaScript在解析代码时,如遇到了var声明的参数就会将他们提升到作用域顶部声明,如遇到了let跟const在执行到它们的声明代码时都会将它们放到TDZ(暂死区),调用暂死区的参数就会出现报错。
二.不能重复声明
在ES6之前,使用var可以对同一个作用域内的同名参数多次重复声明,这是一种非常病态的情况。ES6中,使用let跟const声明的参数在同一个作用域中是无法重复声明的。
let a = '1'function func(){ let a = '2' let a = '3'}func()
//SyntaxError: Identifier 'a' has already been declared复制代码
三.不会绑定全局
var value = 1;
console.log(window.value); // 1
let value = 1;
console.log(window.value); // undefined复制代码
对于const的误解
const用于声明常量,const声明的绑定对象是不能更改的,但const绑定的值确是可以更改的。
const a = { name: 'xiaoming', age: 22}
a.name = 'xiaowang'
console.log(a);// { name: 'xiaowang', age: 22 }复制代码
临时死区
ES6 明确规定,如果区块中存在let
和const
命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
let a = 'a'{ console.log(a); let a = 'b'}
// ReferenceError: Cannot access 'a' before initialization复制代码
在一个封闭的块作用域中,a被let声明了,a参数就会被放入临时死区,只有执行let a=‘ b’
之后a才会被从死区中调出,在此之前无论外层的作用域是否声明了a只要调用了a就会报错。
循环中的块级作用域
var funcs = [];
for (var i = 0; i < 3; i++) {
funcs[i] = function () {
console.log(i);
};
}
funcs[0](); // 3复制代码
var funcs = [];
for (let i = 0; i < 3; i++) {
funcs[i] = function () {
console.log(i);
};
}
funcs[0](); // 0复制代码
ES6对循环中的let与var的处理是完全不同的。就是在 for (let i = 0; i < 3; i++)
中,即圆括号之内建立一个隐藏的作用域。上述代码可以等价于:
{
let i = 0
funcs[i] = function () {
console.log(i); };
}
{
let i = 1
funcs[i] = function () {
console.log(i); };
}
{
let i = 2
funcs[i] = function () {
console.log(i); };
}复制代码
小结
关于let跟var的面试题有很多,只要弄清楚块作用域和提升声明应该就没什么问题。。。。。大概=-=