我的回答
let的特性
- 在块级作用域内有效
 - 不能重复声明
 - 不能预处理,不存在变量提升,即未声明之前的代码不能调用
 
用匿名函数的作用域来模拟块级作用域,将用到let的代码放到匿名函数中,就不会造成变量污染了
(function(){var c =3console.log(c) //1})()
const的特性
const用于声明一个常量
- 在块级作用域内有效
 - 不能重复声明
 - 不能预处理,不存在变量提升,即未声明之前的代码不能调用
 - 不能修改(要注意,数组和对象属于引用数据类型,const保存的是指向对象的指针,所以修改其中的属性时指针不变,可以修改)
 - 使用时必须初始化(必须赋值)
 
数据属性
- configurable:是否可以被 delete 删除或者改变特征值
 - enumerable:是否能通过 for-in 循环遍历返回属性
 - writable:是否可以修改属性的值
 - value:保存这个属性的数据值
 
访问器属性
- configurable:能否通过 delete 删除,能否修改属性特性
 - enumerable:能否通过 for-in 循环返回属性
 - getter:读取属性时调用的函数,默认为 undefined
 - setter:写入属性时调用的函数,默认为 undefined
 
对于不可重复赋值,我们可以设置其configurable为false,同时 set中判断是否重复赋值,如果是即报错,而块级作用域可以用对象作为容器创造函数作用域代替 而如何修改这些属性呢,可以使用Object.defineProperty() 方法
Object.defineProperty(obj, prop, descriptor):会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
obj:要定义属性的对象
prop:要定义或修改的属性的名称
descriptor:要定义或修改的属性描述符
function _const(key, value) {window[key] = value;Object.defineProperty(window, key, {enumerable: false,configurable: false,get: function () {return value;},set: function (newValue) {if (newValue !== value) {throw TypeError("这是只读变量,不可修改");} else {return value;}},});}
参考回答
ES6 let、const 块作用域实现原理
作用域是指在运行时代码中某些特定部分中变量、函数和对象的可访问性。可以这样理解:作用域就是一个独立的地盘,让变量不会外泄、暴露出去;也就是作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突
编译阶段
- 通过 var 声明的变量,会提升到函数变量环境中
 
- let、const 声明的变量会被推入词法环境中
 
- 代码执行到代码块,在代码块内,通过 let、const 声明的变量会被推入到词法环境,因此在代码块内这些变量是可访问的
 
// babel转换后的代码 var a = 2; { var _a = 3; console.log(_a); // 3 } console.log(a); // 2 // 可以看到使用的是babel的转换是使用var
<a name="BAyld"></a>#### 通过立即执行函数实现 let```javascriptvar a = 2;(function () {var a = 3;console.log(a); // 3})();console.log(a); // 2
通过 object.defineProperty(obj,prop,desc)实现 const
由于 ES5 环境没有 block 的概念,所以是无法百分之百实现 const,只要挂载到某个属性下,要么是全局的 window 要么就是自定义一个 object 来当容器
function _const(data, value) {Object.defineProperty(window, data, {enumerable: false,configurable: false,get: function () {return value;},set: function (data) {throw new TypeError("Assignment to constant variable.");},});}_const("a", [1, 2]);a = [3, 4]; // 报错a.push(3);
注意事项
const 实际上保证的并不是变量的值不许改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数值,值就保存在变量指向的内存地址,因此等同于常量。
但是对于复杂类型的数值(数组,对象等),变量指向的内存地址,保存的是一个指向实际数值的指针,const只能保证这个指针式固定的(即是总指向另一个固定的地址),至于它指向的数据结构是不是可变的就说不清楚了。因此,将一个对象声明为常量的时候就必须小心使用了。
