前端秘籍 ES 6 第一篇 ——— let 、 const 与 var 声明

76 阅读3分钟

关于 JS 引擎在编译阶段是如何处理变量声明相关的内容可以参考另一个系列 深入理解 JS 执行原理 中的 执行上下文 !这篇文章。

let 、 const 与 var 之间的区别

var

var 声明的变量存在变量提升,即在声明该变量之前就可以使用,值为 undefined ,其作用域为全局;

let 和 const

let 用法类似于 var ,但是所声明的变量,只在 let 命令所在的代码块内有效;

const 只能用来声明常量,一旦赋值,不能修改,故使用 const 不能只声明不赋值;

区别

var 和 let 的区别

使用 var 声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象;
使用 let 声明的变量,其作用域为该语句所在的代码块内,且相同作用域内不可以重复声明同一个变量;

let 和 const 的区别

let 声明的变量可以重新赋值,而 const 声明的是一个常量,一旦赋值就不可再变,所以声明时就要赋值;

总结

var 声明的变量在声明语句之前可以使用,letconst 不可以;
var 对同一个标识符可以重复声明,letconst 不可以;
var 声明的变量可以在函数内部全局使用,letconst 有块作用域,只在语句所在的代码块起作用;
const 声明的是常量,不可以重新赋值;

变量提升

所谓的变量提升,是指在 JavaScript 代码执行过程中,JavaScript 引擎把变量的声明部分和函数的声明部分提升到代码开头的“行为”。变量被提升后,会给变量设置默认值,这个默认值就是我们熟悉的 undefinedletconst 声明的变量实际上有也有变量提升的行为,与 var 声明的变量不同之处在于未被初始化(即赋值 undefined )。

暂时性死区

ES6 明确规定,如果区块中存在 letconst 命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

总之,在代码块内,使用 let 命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。

问题: const 声明一个对象,还可以新增对象的属性或修改对象中属性的值吗?

答:可以,引用类型的数据实际存储的是一个引用地址,这个地址指向一个对象。不可变的只是这个地址,即不能把已声明的常量指向另一个地址,而对象本身是可变的,新增/修改属性都不会引起地址值的变化,故不会报错;

本质:const 实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于引用类型的数据,变量保存的只是一个指向堆中实际数据的指针,const 只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。

拓展:已定义的对象不希望被修改,该如何做?

// 使用 Object.freeze 方法冻结对象,冻结后的对象不可添加新属性(常规模式下无效,严格模式下报错)
const obj = {
     name: 'xiaolonga',
     age: 18,
 }
Object.freeze(obj);
console.log(obj, 'obj');
obj.age = 19;
// 报错
console.log(obj, '修改属性');
obj.career = 'web前端工程师';
// 报错
console.log(obj, '添加属性');