let 和 const命令
- let 命令
- 块级作用域
- const命令
1.let命令
ES6新增了let命令,用来声明变量,但是let声明的变量只在let命令所在的代码块有效。
{
let a = 10;
var b = 1;
}
console.log(b); //1
console.log(a); // 报错
上面的代码之中,用了let和var来定义变量,然后再代码块之外调用变量,结果let声明报错,这说明了let明治旨在代码块之内有效。
for循环的计数器,适合使用let命令。
for (let i = 0; i < 10; i++){
//...
}
console.log(i); //ReferenceError:
上述代码中,i 只在for循环体内有效,在循环体外引用就会报错
var arr = [];
for (var i = 0; i < 10; i++){
a[i] = funciton(){
console.log(i);
}
}
a[6]() = 10;
上述代码中,i是var来声明的,在全局范围内都有效,所以全局只有一个变量i。每一次循环,i的值都会改变,,而循环内被赋给数组a 的函数内部的console.log(i),里面的i指向的就是全局的i。也就是说,所有数组a的成员里面的i,指向的都是同一个i,导致运行时输出的是最后 一轮的i的值,也就是 10。
如果使用let ,变量的声明只在作用域内有效。
var arr = [];
for (let i = 0; i < 10; i++){
a[i] = funciton(){
console.log(i);
}
}
a[6]() = 6;
上面代码中,变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。你可能会问,如果每 一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。
2.块级作用域
为什么需要块级作用域?
在ES5中,只有函数作用域和全局作用域,没有块级作用域。let 命令实际上就是新增了块级作用域。
function fn(){
let n = 10;
if(true){
let n = 100;
}
console.log(n);//10
}
上述代码有两个代码块,即两个用{}包裹的内容。这表示外层代码不受内部代码的影响,如果两次都用var 定义变量n ,最后输出的结果是100。
块级作用域可以任意嵌套
{{{{let a = 10;}}}}
外部作用域无法读取内部作用域内的变量
{{{{let a = 10;}
console.log(a);//报错
}}}
3.const命令
基本用法
const 声明一个只读的变量。一旦声明,常量的值就不能改变。
const a = 1;
a // 1
a = 10;//报错
用const声明的变量不能改变值,改变常量的值会报错。
这意味着,从const 一旦声明,就立刻要赋值。
const 的作用域与let 相同:只在声明所在的块级作用域内有效
const 只声明,不赋值,就会报错。
本质
const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在 变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const只能保 证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了
const foo = {};
//为foo添加一个属性,可以成功
foo.prop = 123;
//将foo 指向一个新对象,就会报错
foo = {};
上述代码中,常量foo储存的是一个地址,这个地址指向一个对象。这个地址是不能改变的,即为不能把这个地址指向其他地方,但是对象本身是可变的,依然可以为对象增加新属性。
const a = [];
a.push('Hello'); // 可执行
a.length = 0; // 可执行
a = ['Dave']; // 报错
不能把地址指向其他地方。