let 和var类似都是用于声明变量,但是let声明的变量只在let命令所在的代码块中有效。
{
let a = 12;
var b = 11;
}
a // ReferenceError: a is not definded
b // 11
不存在变量提升
var命令会发生变量声明提升,即变量可以在声明之前被使用,值为undefined。而通过let命令声明的变量在声明之前不可以被调用,如果在声明之前调用就会报错。
console.log(foo); // undefined
var foo = 123;
console.log(bar); // 报错
let bar = 123;
暂时性死区 只要块级作用域内存在let声明的变量,那么在这个变量被let声明之前,他是不可用的,如果调用就会报错。
var aa = 12;
if(true) {
aa = 1222; // 报错
let aa = 121;
}
ES6明确规定,如果区块中存在let和const命令,则这个区块对这些命令声明的变量从一开始就形成了封闭作用域,只要在声明之前使用这些变量就会报错。这样的设计就是让大奖养成良好的编码习惯,变量一定要先声明在使用。
不允许重复声明
let 不允许在相同的作用域里面重复声明同一个变量。
{
var a = 12;
let a = 1223; // 报错
}
{
let a = 12;
let a = 122;// 报错
}
// 在函数内部不能重复声明参数,同时也说明函数参数是默认声明的变量,作用域和函数体相同。
function fnc(arg){
let arg;// 报错
}
const命令
const命令声明一个只读的常量。一旦声明就不能改变。
const PI = 3.14;
PI = 3;// 报错
const声明的变量不能改变值,这意味着const声明的变量一旦声明就要立即初始化。
const lee;//报错
除此之外,const和let 一样不会变量提升,存在暂时性死区,也不能被重复声明。
const的本质实际上保证的不是变量的值不得改动,而是变量指向的内存地址不得改动。对于简单类型的数据(数值,字符串,布尔值,null,undefined)而言,值就保存在变量指向的内存地址中,因此等同于常量。但对于复合类型的数据而言(对象,数组等),变量指向的内存地址保存的只是一个指针,const只能保证这个指针是固定不变的,至于他指向的数据结构是不是不变的,这完全不能控制。因此在将对象声明为常量的时候要小心。
// 可以成功为obj添加prop属性。
const obj = {};
obj.prop = 12;
obj.prop // 12;
如果真的想将对象冻结,应该使用Object.freeze方法。
const foo = Object.freeze({});
// 常规模式下,下面这行代码不起作用,但是在严格模式的时候下面这行代码还会报错
foo.prop = 123;
上面的代码中,常量foo指向一个冻结的对象,所以添加新属性时不起作用。严格模式还会报错。除了将对象本身冻结,对象的属性也应该冻结。 下面是一个将函数彻底冻结的函数。
let constantize = (obj)=>{
Object.freeze(obj);
Object.keys(obj).forEach((key)=>{
if(typeof obj[key] === "object") {
constantize(obj[key]);
}
});
}
顶层对象的属性
在ES5中,使用var声明的全局变量同时也是顶层对象window的属性。但是从ES6开始使用let和const声明的变量开始于顶处对象脱钩,即使用let和const声明的变量不在是window对象的属性。
var a = 12;
window.a; // 12
let b = 123;
window.b // undefined
window.c = 555;
c // 555
window对象的属性相当于全局变量,但是他和使用var let const声明的变量还是有区别的,window对象的属性可以通过delete操作符删除,而使用var 声明的变量不可以被删除。
delete window.a // false 删除失败
window.d = 222;
delete window.d // true 删除成功
函数声明的全局函数和var 声明的变量有类似的情况,可以通过window对象调用与函数同名的方法。但是不能通过delete删除。
function fnc(){};
window.fnc // function fnc(){}
delete window.fnc // false 删除失败
而ES6中,通过class声明的构造函数 不再是window对象的属性了,当然也不能被delete删除。
class fnc1{};
window.fnc1 // undefined
delete window.fnc1 // true 注意 !!! delete 删除不存在的变量时和属性时会返回true
作用域
在ES6之前,JavaScript是没有块级作用域这个概念的。那时候只有全局作用域和函数内部的局部作用域。ES6增加了
let和const命令,使得JavaScript有了块级作用域的概念。
转眼转行前端快(和谐) 3年(自学半年,在小公司蹉跎半年,真正工作两年)了,这三年书也买了不少,看了不少,教程、文档也没少看,主流前端框架都会用,但是就是组织不起来自己的知识体系,面对茫茫多的前端知识,很多都是貌似熟悉,真正去解释描述的时候,很多都是是是而非,所以想通过这样的一个笔记,盘点一些重要的前端知识点,算是工作学习的一个印记吧。
未完待续
To be continue...