let 和 const
2019-04-11 本文已影响0人
CRJ997
作用域
在ES6之前,并没有块级作用域这种概念,有的只有函数作用域和全局作用域。然后变量的声明方式来讲,也就只有var。但是var 声明的变量由于存在变量提升这个机制,导致var声明的变量都会在整个作用域(整个函数作用域或者全局作用域)中可见。为了减少对作用域命名空间的污染和规避冲突,也就引入了let这个关键词。
- 不过实际上通过try和with实际上是建立了块级作用域的,但是这个概念确实不普遍
//例如使用with把一个对象的作用域扩展到当前作用域时,相当于一个块级作用域
var a = 90;
var obj = {
a:8;
b:10;
};
with(obj){ //这一部分就类似于块级作用域
console.log(a); //这边的a覆盖外部的a定义
console.log(b);
}
console.log(a);//外部无法访问obj内部的a
let 的使用
和var的用法相同,但是并不存在变量提升。也就是下面的代码会导致Reference error
错误
console.log(a);// Uncaught ReferenceError: a is not defined at index.html:9
let a = 9;
- 使用的注意事项
当使用let关键字把变量绑定在一个已经存在的块作用域上的时候,这种行为是隐式的。在开发和修改代码的过程中,如果没有密切关注哪些块级作用域中有绑定的变量,并且习惯性地移动这些块或者将其包含在其他的块中,就会导致代码的混乱(实践不够不太理解...)
比较有用的用法:
-
使垃圾回收没有顾虑
考虑下面的代码,这些代码包含在一个函数作用域中的话
function process(data){
//do something
}
var someReallyBigData = {....};
processs(someReallyBigData);
var btn = document.getElementById('myButton');
btn.addEventListener('click',function click(event){
console.log('button clicked');
},false);
click函数的点击回调并不需要someReallyBigData变量,理论上来讲这意味着当process(...)执行完成后,在内存中占用大量空间的数据结构就可以被垃圾回收了。但是,由于click函数形成了一个覆盖整个作用域的闭包,因此JS引擎极有可能仍然保存着这个结构(取决于具体实现)
这时候可以这么做:
用{}把这个比较大的数据结构括起来,用let定义someReallyBigData:
function process(data){
//do something
}
//这里声明块级作用域,就很显式的告诉垃圾回收机制,这个地方的内存在结束之后可以马上回收
{
let someReallyBigData = {....};
processs(someReallyBigData);
}
var btn = document.getElementById('myButton');
btn.addEventListener('click',function click(event){
console.log('button clicked');
},false);
垃圾回收机制也就没有顾虑了
-
let 循环
for循环中定义循环变量。
for(let i=0;i<10;i++){
console.log(i);
}
console.log(i); //Reference Error
let在for循环中的作用:
- 不仅仅把i绑定到for循环的块中,事实上它将其重新绑定到了循环的每一个迭代中,确保使用上一个循环迭代结束时的值重新进行赋值。(也就是循环的每一次都执行一次let i的重新声明)
也就是上面的代码类似于下面:
{
let j;
for(j=0; j<10;j++){
let i=j; //每个迭代都重新绑定
console.log(i);
}
}
说说const
- 首先const创建的也是块级变量
- 正如其名,常量
可以看看const定义和其ES5等效代码:
//ES6
const a = 10;
//ES5
Object.defineProperty(this,'a',{
configurable:false,
enumerable:true,
writable: false,
value: 10
}