let和const命令
目录1. let命令
- let命令的用法和var类似,其核心特点为只在let所在的代码块内有效。由此衍生出几个特点:
-
不存在变量提升
- 变量提升是指,变量可以在声明之前使用,此时值为undefined
- let所声明的变量一定要在声明后使用,否则会报错
-
不允许重复声明
//var的情况 console.log(foo); //输出undefined var foo = 2; var foo = 3; console.log(foo); //输出3 //let的情况 console.log(bar); //报错 let bar = 2; let bar = 3; //报错
-
2. const命令
-
const声明一个只读的常量,一旦声明,常量的值就不能变
const的特性与let极为相似,包括只在命令所在的代码块内有效、不会提升、不允许重复说明
-
const常量一旦声明就必须立刻初始化,否则就会报错
const foo; //报错 const foo = 5; //正确
-
将一个数组或对象声明为常量需要小心。和java中的指针一样,const所保证的实际上并不是变量的值不得改动,而是变量指向的内存地址所保存的数据不得改动。正如java中const只能保证指针指向方向,而不能保证所指方向的数据内部能否改变一样。
3. 块级作用域
-
ES5中只有全局作用域和函数作用域,这样就很容易造成变量之间的覆盖或泄露
let为JS新增了块级作用域,它和Java中的局部作用域有相似之处:
- 外层代码块不受内层代码块影响
- 外层作用域无法读取内层作用域的变量
- 内层作用域可以定义外层作用域的同名变量
function f1() { let n = 5; if (true) { let n = 10; } console.log(n); // 5 }
-
注意:
-
由于各种原因,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句
-
ES6的块级作用域必须有大括号,如果没有大括号,JS引擎就不认为存在块级作用域
// 第一种写法,报错 if (true) let x = 1; // 第二种写法,不报错 if (true) { let x = 1; }
在上面的代码中,由于let只能出现在当前作用域的”顶层“,而第一种写法将他作为全局作用域中if的子语句,并非”顶层“,所以报错
-
4. 从function循环问题深入了解let
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); //输出10
-
这段代码中,由于i是全局变量,存在变量提升,所以值会一直更迭到10
由于function中储存的是变量i,而不是具体数值,所以一旦调用,就会寻找到变量i的地址,最后得出结果10
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); //输出6
-
这段代码中,由于变量
i
是let声明的,所以当前的i
只在本轮循环有效,即每一次循环的i
其实都是一个新的独立的变量(这一点和Java中的很不一样)当function调用时,会寻找当时存储的那个独立的i的地址,所以最后输出的是6。
-
更多可以得知的信息
- i在离开作用域后并不会被立即销毁,这点和java中的局部变量不一样
- JS引擎内部会记住上一轮循环的值,初始化本轮的
i
时,就会在上一轮的基础上计算。这样for循环就能正常迭代i
的值 - for由两个作用域组成:一个父作用域(设置循环变量部分)和一个子作用域(循环体内部),两个作用域是不相冲突的,都可以设置同名let变量