每天都提供一道关于前端面试中常见的题目。
今日题目:
说一下 let、const 的实现,使用ES5模拟实现以下。
题解:
一、ES6 let、const块作用域实现原理
作用域是指在运行时代码中的某些特定部分中变量、函数和对象的可访问性。可以这样理解:作用域就是一个独立的地盘,让变量不会外泄、暴露出去。也就是说作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突。
1.1 编译阶段
- 通过
var
声明的变量,会提升到函数变量环境中; - 而
let
、const
声明的变量,会被推入词法环境中; - 在代码块内,通过
let
、const
声明的变量,既不会推入变量环境,也不会推入词法环境
1.2 执行阶段
- 代码执行到代码块,在代码块内,通过
let
、const
声明的变量会被推入到词法环境,因此在代码块内这些变量是可访问的; - 当代码块执行结束时,在代码块内,通过
let
、const
声明的变量会从词法环境中推出,因此在代码块外访问不到这些变量。
二、let、const的实现
let . const 块级声明用于声明在指定块的作用域之外无法访问的变量。let用于声明变量, const用于声明不可改变的常量。
2.1 看下babel的转换
- 源代码
var a = 2;
{
let a = 3;
console.log(a); // 3
}
console.log(a); // 2
- babel转换后的代码
var a = 2;
{
var _a = 3;
console.log(_a); // 3
}
console.log(a); // 2
可以看到使用的是babel的转换是使用var,我们自己来模拟下,可以基于立即执行函数简单模拟let的效果:
2.2 通过立即执行函数实现let
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);
2.4 注意
const 实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const 只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。
我会帮大家把每一天的题目和超级详细的答案整理好