js中的作用域与作用域链

67 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

# js中的作用域与作用域链.

## 作用域与作用域链

首先先看一个例子:

`

                    let x = 1;

		function A(y){
			let x = 2;
			function B(z){
				console.log(x+y+z)
			}
			return B
		}
		let C = A(2);
		C(3);

`

先来看以下,js底层代码执行的一个顺序:

ECstack = [ //执行栈

EC(G)={	//创建全局执行上下文
	VO(G):{	//全局变量对象
	...			//包含全局对象原有的属性
	x=1;
	A=function(y){...}		//创建函数的时候就确定了其作用域  (重点)
	A[[scope]] = VO(G);

} } ]

注:我们不管在哪一个执行上下文当中,除了创建变量或者堆以外,同时给当前的函数,声明了它所在的作用域是谁。

看上方例子,函数A在全局创建的,那么A的作用域就是全局的执行上下文。当A执行的时候,就会生成一个新的执行上下文(每个函数执行都会生成一个私有的执行上下文)。

此时,在A的执行上下文,我又创建了一个B函数。那么B也会生成一个私有的执行上下文,同时B的作用域也会被创建,那么B是在A的执行上下文创建的,那么B的函数作用域就是,当前这个A的执行上下文。

函数在执行上下文,除了获取arguments(实参对象),生成作用域外,还做了一件事,生成this指向
函数执行,有个执行主体,进来的第一件事情就是声明this指向,this指向后面说。

除此之外,它还初始化了它的链表,也就是我们常说的作用域链。作用域链的查找规则,就是上面加粗的文字。

下面总结一下:

函数的执行机制:

创建函数的时候:

(1)创建一个堆(存储代码字符串和对应的键值对)
(2)初始化了当前函数的作用域[[scope]]

作用域[[scope]]指的是所在上下文EC中的变量对象VO(变量对象)/AO(函数内的变量对象) 严格来说的话。作用域[[scope]] 与执行上下文是有区别的,作用域指的是当前上下文具体的存放变量的地方,上下文是既可以存变量,又能压缩代码放到执行栈执行的。但是,编程中,我们认为他们俩没啥区别,其实也是不会出错的。

函数执行的时候

创建一个新的执行上下文EC,并且压缩至栈(EC stack)里执行。

初始化this指向

初始化作用域链

创建AO变量对象存储变量

变量又会进行 arguments(它是函数运行时的实参对象) =》 形参 --》如果有变量提升,将变量提升,如果没有变量提升,会将代码执行。

下面看一下,上面题闭包的形成,以及作用域链的查找方式

20200331130501385.png

重:

创建函数的时候,形成的是作用域,以及作用域是谁,函数执行的时候,一定会先初始化好它的作用域链,代码执行当中,遇到一个变量,首先看看它是不是私有变量,如果是,用自己的,如果不是,就会沿着作用域链,一级一级往上查找,一直查找到全局位置,找不到就会报错。这就是闭包,作用域链的一个查找过程。