4 / 6 聊聊作用域链

前面的话

前端日问,巩固基础,不打烊!!!

解答

先来说几个概念:

  • 变量对象:保存了执行上下文中的变量和函数声明

  • 在全局执行上下文中,变量对象就是全局对象(一般指window对象)。
    在。

  • 在函数执行上下文中,变量对象用AO表示。

函数执行上下文中的AO

函数的执行上下文在调用时被创建,创建之后分为两个阶段:进入执行上下文执行代码。这两个过程的AO会有一定的差异,下面通过例子来分析:

function foo(a) {
  var b = 2;
  function c() {}
  var d = function() {};
  b = 3;
}
foo(1);

当执行foo函数时,会创建相应的执行上下文。

  • 进入执行上下文

    这时的AO包括: arguments对象函数的所有形参(如果有实参就为实参的值)、函数声明变量声明

    AO = {
    	arguments: {
    		0:1,
    		length: 1
    	},
    	a: 1,
    	b: undefined,
    	c: reference to function c(){},
    	d: undefined
    }
    
  • 执行代码

在代码执行阶段,会顺序执行代码,然后改变AO对象中的值,当代码执行完毕之后,对应的AO会变为:

AO = {
	arguments: {
		0:1,
		length: 1
	},
	a: 1,
	b: 3,
	c: reference to function c(){},
	d: reference to FunctionExpression "d"
}
总结
  • 全局执行上下文的变量对象就是全局对象
  • 函数执行上下文的变量对象是AO;进入函数执行上下文时,AO会包括arguments对象,函数形参(如果有实参则为实参值,否则为undefined)、函数声明、变量声明(undefined); 代码执行时,根据代码的顺序修改对应的属性值。

作用域链

定义:由多个执行上下文的变量对象构成的链表。

通俗来说,比如一个函数里面,访问了一个变量,先从其AO对象中找,如果没有的话就从其父级的中的AO对象中找,最终找到全局对象。

函数创建时:

函数有一个内部属性[[scope]], 当函数创建时,就会保存所有父级的变量对象到其中。

举个例子:

function foo() {
    function bar() {
        ...
    }
}

函数创建时,各自的[[scope]]为:

foo.[[scope]] = [
  globalContext.VO
];

bar.[[scope]] = [
    fooContext.AO,
    globalContext.VO
];
函数被调用时

当函数被调用时,会创建函数执行上下文,将自身的AO对象添加到作用域链的前端。

此时再来看一下上面两个函数的作用域链:

foo.[[scope]] = [
  AO,
  globalContext.VO
];

bar.[[scope]] = [
	AO,
    fooContext.AO,
    globalContext.VO
];

参考文章:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章