我的回答
let的特性
- 在块级作用域内有效
- 不能重复声明
- 不能预处理,不存在变量提升,即未声明之前的代码不能调用
用匿名函数的作用域来模拟块级作用域,将用到let的代码放到匿名函数中,就不会造成变量污染了
(function(){
var c =3
console.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
```javascript
var 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只能保证这个指针式固定的(即是总指向另一个固定的地址),至于它指向的数据结构是不是可变的就说不清楚了。因此,将一个对象声明为常量的时候就必须小心使用了。