再次深入执行上下文

全局上下文

预定义的对象,可以访问其他所有预定义的对象、函数和属性。在顶层JS中,可以用关键字this引用全局对象(Window对象)。全局对象是由Object构造函数实例化的一个对象。全局上下文中的变量对象(VO)就是全局对象。
### 函数上下文
AO(activation object,AO)变量对象,变量对象(VO)与活动对象其实是一个东西,当进入到一个执行上下文中,这个上下文的变量对象被激活,所以叫做活动对象,只有活动对象才能被访问。活动对象在进入上下文中通过arguments属性初始化。
### 执行上下文
执行代码前变量对象包括:
1.函数的所有形参
由名称和对应值组成的一个变量对象的属性被创建
没有实参,属性值设为undefined
2.函数声明
由名称和对应值(函数对象)组成一个变量对象的属性被创建
如果变量对象已经存在相同名称的属性,则完全替换这个属性
3.变量声明
由名称和对应值(undefined)组成一个变量对象的属性被创建
如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性
代码执行时会顺序执行代码,根据代码修改变量对象的值
### 小结
1.全局上下文的变量对象初始化是全局对象
2.函数上下文的对象初始化只包括Arguments对象
3.在进入执行上下文时会给变量对象添加形参、函数声明、变量声明等初始的属性值
4.在代码执行阶段,会再次修改变量对象的属性值

再次深入作用域链

查找变量时,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象,由多个上下文的变量对象构成的链表就叫做作用域链
### 函数创建
函数的作用域在函数定义的时候就决定了。函数创建时会保存所有父级变量对象到其中,可以理解[[scope]]就是所有父变量对象的层级链,但不代表完整的作用域链。
### 函数激活
函数激活时,创建VO/AO后,会将活动对象添加到作用链的前端。
Scope为执行上下文的作用域链。
### 深入理解函数创建到执行
1.创建函数,保存作用域链到函数Scope
2.准备执行函数,创建函数执行上下文,将其压入执行上下文栈
3.函数不立即执行,复制函数Scope创建作用域链
4.用arguments创建AO,然后初始化,加入形参、函数声明、变量声明
5.将AO压入函数作用域链顶端
6.执行函数,修改AO的属性值
7.查找到AO值,函数执行完毕后,函数上下文从执行上下文栈中弹出

针对闭包基础的理解和使用

什么是闭包

闭包允许函数访问并操作函数外部的变量。只要变量或函数存在于声明函数时的作用域内,闭包即可使函数能够访问这些变量或函数。
调用一个函数时,会为这个函数调用创建一个执行上下文,并创建一个作用域链。然后用arguments和其他命名参数来初始化这个函数的活动对象(AO)。外部函数的活动对象是内部函数作用域链上的第二个对象。这个作用域一直向外反串起了所有包含函数的活动对象,直到全局执行上下文才终止。

闭包使用例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Ninja() {
var feints = 0;
this.getFeints = function(){
return feints;
};
this.feint = function(){
feints++;
};
}

var ninja1 = new Ninja(); //赋值一个实例
ninja1.feint(); //undefined 通过实例无法直接获取该变量值,但是能调用方法去改变变量值
assert(ninja1.feints === undefined,
"And the private data is inaccessible to us.");
assert(ninja1.getFeints() === 1,// 通过作用域内的方法获取私有变量的值,但是无法对该值进行直接操作
"We're able to access the internal feint count.")
var ninja2 = new Ninja();//新的实例有自己的私有变量
assert(ninja2.getFeints() === 0,
"The second ninja object gets it’s own feints variable.");

闭包的特性

1
2
3
4
类似于“气泡”效果,每个实例都有一个单独的闭包,不能访问其他闭包中的变量,作用域(scopes)强相关。
关于执行上下文栈:上下文在变化。每次执行新的函数,都将创建新的函数上下文。内部代码结构可以访问外部代码结构中定义的变量。
查找变量是从内往外根据环境来查找数据,直到外层环境global还未找到则返回错误。
词法环境:块级环境,函数环境,全局环境

JS执行

1
2
3
4
5
JS引擎会访问并注册在当前词法环境中所声明的变量和函数。JS在第一阶段完成后开始执行第二阶段,具体执行取决于变量的类型(let,const,var,函数声明)以及环境类型(↑词法环境)。
var myFunExper = funtion(){};//指向语数表达式(无法在声明前访问函数)
var myArrow = (x) => x;//指向箭头表达式(无法在声明前访问函数)
function fun(){}//作为函数声明进行定义(可以在声明前访问函数)
变量提升!!

过程

闭包小结

1
2
3
4
5
闭包的高级功能:通过构造函数内的变量以及构造方法来模拟对象的私有属性;处理回调函数,简化代码。
上下文栈的创建,推入,退出。
JS引擎通过词法环境跟踪标识符(词法环境:俗称作用域)。
var 定义距离最近的函数级变量或全局变量
let和const定义距离最近级别的变量,包括块级变量。