我正在参加「掘金·启航计划」
预编译的理解:
预编译的步骤(AO):
- 查找形参和变量声明,把他的值声明为undefined
- 将实参的值赋给实参
- 寻找函数声明
- 执行函数
GO的执行过程:
- 生成了一个GO的对象
- 找形参和变量声明,将他作为GO属性名值为undefined
- 在函数体中找函数声明,值赋给函数体
AO是啥? 函数的执行期上下文(预编译时已经被定义) GO是啥? 全局的执行期上下文(未执行已经被定义)
那到底是先执行AO还是先执行GO呢? 应该是先执行全局,先生成GO,在函数执行的那一刻生成AO(预编译的过程),在找值的过程中,如果有几层嵌套关系,近的优先,先找AO,最后找GO 试着用三个案例学会预编译~
function test(){
return a; // 终止函数运行
function a(){}
var a = 2;
}
console.log(test())
这段代码在预编译的过程中是怎么执行的呢?
他在预编译的过程中会有一个AO对象
AO = {
a:undefined -> function a(){}
}
再来 看一个例子
console.log(test())
function test(){
a = 1;
function a(){}
var a = 2;
return a;
}
他的执行结果又是怎样的呢?
AO = {
a:undefined -> function a(){} -> 1 -> 2
}
a = 1;
function test(e){
function e(){}
arguments[0] = 2;
console.log(e);//2
if(a){
var b = 3;
}
var c;
a = 4;
var a;
console.log(b);//undefined 因为这里的a为false
f = 5;//f未声明,挂载到GO上
console.log(c);//undefinde
console.log(a);//4
}
var a;
test(1);
console.log(a);//1 GO优先于局部的AO
console.log(f);//5
他的执行结果又是怎样的呢?
全局的GO
GO = {
a:undefined ->1
test : function test(){...}
f:5
}
生成GO后会生成局部的AO
AO = {
e: undefined ->1(实参的值赋给实参)->function e(){}->2
b:undefined
c:undefined
a:undefined -> 4
}
注意:预编译中找变量声明不会看代码的执行过程,比如if else等,在执行的过程中才会看变量赋值
作用域的理解
因为函数可以访问他的属性,我们可以将函数理解为 对象的一种,还记得刚开始学编程的时候有一句话印象很深刻,万物皆对象,当然对象中也有我们无法访问的固有属性,我理解为浏览器提供的方法都是固有属性
[[scope]]就是无法访问的其中一个对象,叫作用域
- 函数创建时,生成的一个JS内部的隐式属性
- 函数存储作用域链的容器,而作用域链里存储的就是AO和GO
- 函数执行以后AO要被销毁,每次执行函数都会生成一个新的AO(AO是一个即时的存储容器)
作用域链:当[[scope]]中所存储的执行期上下文对象的集合呈现链式结构就是作用域链
执行期上下文:当函数在执行的前一刻,会创建一个称为执行期上下文的内部对象。 一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,执行上下文被销毁。
function a(){
function b(){
var bb = 23;
aa = 0;
b()
console.log(aa)
}
var aa = 123
b()
console.log(aa)
}
var go = 100
a()
bb 的 AO 是拿到 aa 的 AO,就是同一个 AO,bb 只是引用了 aa 的 AO,GO 也都是同一个。function b(){}执行完,干掉的是 b 自己的 AO(销毁执行期上下文)(去掉连接线),下次 function b 被执行时,产生的是新的 b 的 AO。b 执行完只会销毁自己的 AO,不会销毁 a 的 AO。function a(){}执行完,会把 a 自己的 AO 销毁 【会把 function b 也销毁】,只剩 GO(回归到 a 被定义的时候),等下次 function a再次被执行时,会产生一个全新的 AO,里面有一个新的 b 函数。。。。。。周而复始
注意:在全局执行的前一刻(GO)函数声明已经定义,但是函数表达式并没有定义