技术实践

var怎么实现 let

ES6之前,ES的作⽤域只有两种:全局作⽤域和函数作⽤域,是不⽀持块级作⽤域的

羊先生的头像
羊先生2022.03.09 · 5 分钟阅读 · 87 阅读
var怎么实现 let封面
文章正文还需 5 分钟

我们先解决这个问题,为什么要引⼊let和const?

作⽤域(scope)

作⽤域是指在程序中定义变量的区域,该位置决定了变量的⽣命周期。

作⽤域就是变量与函数 的可访问范围,即作⽤域控制着变量和函数的可⻅性和⽣命周期。

ES6之前,ES的作⽤域只有两种:全局作⽤域和函数作⽤域,是不⽀持块级作⽤域的

全局作⽤域中的对象在代码中的任何地⽅都能访问,其⽣命周期伴随着⻚⾯的⽣命周期。
函数作⽤域就是在函数内部定义的变量或者函数,并且定义的变量或者函数只能在函数内部被访问。函数 执⾏结束之后,函数内部定义的变量会被销毁。

JavaScript是如何⽀持块级作⽤域的

js 复制代码
function foo(){
	var a = 1
	let b = 2
	{
	let b = 3
	var c = 4
	let d = 5
	console.log(a)
	console.log(b)
	}	
	console.log(b)
	console.log(c)
	console.log(d)
}
foo()

第⼀步是编译并创建执⾏上下⽂

image.png

当进⼊函数的作⽤域块时,作⽤域块中通过let声明的变量,会被存放在词法环境的⼀个 单独的区域中,这个区域中的变量并不影响作⽤域块外⾯的变量,⽐如在作⽤域外⾯声明了变量b,在该作 ⽤域块内部也声明了变量b,当执⾏到作⽤域内部时,它们都是独⽴的存在。

在词法环境内部,维护了⼀个⼩型栈结构,栈底是函数最外层的变量,进⼊⼀个作⽤域块后,就会把 该作⽤域块内部的变量压到栈顶;

当作⽤域执⾏完成之后,该作⽤域的信息就会从栈顶弹出,这就是词法环 境的结构。

当执⾏到作⽤域块中的console.log(a)这⾏代码时,就需要在词法环境和变量环境中查找变 量a的值了

沿着词法环境的栈顶向下查询,如果在词法环境中的某个块中查找到了,就 直接返回给JavaScript引擎,如果没有查找到,那么继续在变量环境中查找。

image.png

点击查看var缺陷以及为什么要引⼊let和const

var 怎么实现 let?

js 复制代码
// 结果输出10 个 10, why?
for (var i = 0; i < 10; i++) {
  setTimeout(function(){
    console.log(i);
  })
}

变量 i 是用 var 声明的,在全局范围内有效,所以全局中只有一个变量 i,当我们用 console.log(window.i) 来检验 i 时,发现 i 为10。每次循环时,setTimeout 定时器里面的 i 指的是全局变量 i ,而循环里的十个 setTimeout 是在循环结束后才执行,所以会输出十个 10

利用函数作用域修改为每个 i 为独立作用域

利用 函数作用域,在每次函数执行过程,中,都将当前的值,传入,每一个函数执行,内部都会声明一个新的参数作用域变量a,每个函数内部的 a 其实是不同的变量

js 复制代码
for (var i = 1; i < 4; i++) {
  (function f(a) {
    setTimeout(function () {
      console.log(a);
    }, 1000);
  })(i);
}