作用域 作用域链

1 作用域(Scope)

1.1 作用域的定义

作用域指的是变量可被访问的有效范围

1.2 作用域的分类

对于 js 来说,作用域有下面三类:

  • 全局作用域

    ​ 变量在全局范围有效。

  • 局部作用域(又叫函数作用域)

    ​ 变量在声明它的函数体中,及在这个函数体嵌套的任意函数体内有效。

  • 块作用域(es6 新增的语法)

    ​ 变量在语句块内有效。

2 变量对象 ( Variable Object )

**变量对象,顾名思义就是保存变量的对象,只要是保存变量的对象,都可以称为变量对象。winows 对象、活动对象、闭包等都是保存变量的对象,都属于变量对象**。

3 活动对象(Activation Object)

活动对象是在函数执行时产生的变量对象,活动对象保存了函数的局部变量、window对象。

4 作用域链 [[scopes]]

作用域链是函数的一个内部属性 [[scopes]],是由函数可访问的所有外部作用域对象组成的数组。[[scopes]] 属性不能通过程序读取,只能由 js 引擎读取。js 通过**作用域链**实现了静态作用域(指作用域由定义时而非运行时决定)。

**作用域链**将可以将不同函数关联起来,并保证了函数解析变量的顺序。

1
2
3
4
function A(aArg){
var aVar = 'aVar';
}
console.dir(A) ;//函数被创建时,会包含一个[[scope]]内部属性,用来保存作用域链

上面代码 chrome 输出截图:

firefox 输出截图:

firefox 并没有输出 [[scopes]] 属性,chrome 虽然输出了,但却无法访问 [[scopes]] 属性。

5 执行上下文(或叫执行环境)

执行上下文是函数执行时创建的一个内部对象,定义了函数执行时的环境。

函数每次执行时,都会创建对应的执行上下文,多次调用函数,将会创建多个执行上下文。当函数执行完毕,执行上下文将被销毁。

执行上下文是使用函数自身的作用域 [[scopes]] 属性来进行初始化的,并将活动对象(由函数的局部变量组成)追加为其第一个元素。

5 总结

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var B1Alias;

function A(){
var aVar = 'aVar';

function B1(){
var bVar='test';
console.log(bVar);
console.log(aVar);
}

B1Alias = B1;
}

A();
B1Alias();
console.dir(B1Alias);

通过上面的示例和调试截图来总结下,将各个概念关联起来:

每个函数被初始化时,会包含一个数组类型的属性 [[Scopes]] (即作用域链),[[Scopes]] 的内容是由此函数可以访问的外部作用域对象组成的。

每次函数执行时,都会创建对应的执行上下文,会使用函数的 [[Scopes]] 来初始化执行上下文,并将活动对象(由函数的局部变量组成)追加到执行上下文的第一个元素。

作用域是一个范围,当把这个范围关联到某个对象时,可以把这个对象叫做作用域对象,如 windows 对象、活动对象、执行上下文 都可以称为作用域对象

保存变量的对象称为变量对象,也就是说变量对象包括了作用域对象,但并不止作用域对象。

参考:

https://juejin.im/post/5b481cc9e51d45192562850f