开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情
-
预编译前奏
JavaScript执行三部曲:
- 语法分析:扫描全部js代码,看看有无语法错误,若有则一行都不执行
- 预编译
- 解释一行执行一行
函数预编译发生在函数执行的前一刻,全局的发生在全局执行的前一刻,所以GO比AO创建早
-
函数预编译
/**
* 函数预编译四部曲:
* 1、创建AO对象(Active Object,块作用域,活跃对象)
* 2、找形参和变量声明,将变量和形参作为AO的属性名,值为undefined
* 3、将实参值与形参统一
* 4、在函数体里找函数声明,值赋予函数体
*/
/**
* 第二步:
* AO {
* a: undefined
* b: undefined
* }
*
* 第三步:
* AO {
* a: 1
* b: undefined
* }
*
* 第四步:
* AO {
* a: function a(){}
* b: undefined
* d: function d(){}
* }
*/
function fn(a) {
console.log(a); // function a(){}
var a = 123; //变量声明已执行,只剩a=123赋值
/**
* AO{
* a: 123
* b: undefined
* d: function d(){}
* }
*/
console.log(a); // 123
function a() { }; // 预编译已看过,不用看
console.log(a); // 123
var b = function () { }; // var b 预编译已看过,执行b = function(){}
/**
* AO{
* a: 123
* b: function(){}
* d: function d(){}
* }
*/
console.log(b); // function(){}
function d() { }; // 预编译看过了
}
fn(1);
全局预编译
/**
* 全局预编译三部曲:
* 1、创建GO对象(Global Object,Window,全局执行期上下文)
* 2、找变量声明,将变量名作为GO的属性名,值为undefined
* 3、找函数声明,值赋予函数体
*/
console.log(test);⑴
function test(test) {⑵
console.log(test);⑶
var test = 234;⑷
console.log(test);⑸
function test() { };⑹
}
test(1);⑺
var test = 123;⑻
解析:函数的预编译发生在函数执行的前一刻,全局的发生在全局执行的前一刻,所以GO比AO创建的早,我们先来全局预编译:
全局预编译:
第二步:GO里有变量test
GO{
test:undefined
}
第三步:函数声明有test,值赋予函数体
GO{
test:function test(test) { console.log(test); var test = 234; console.log(test); function test() { }; }
}
全局执行:
第1行:输出test得function test(test){ console.log(test); var test = 234; console.log(test); function test() { }; }
第2行声明函数,整个函数体不看了
第7行:执行函数,就在执行函数的前一刻,AO对象产生了
第8行:执行test = 123
GO{
test:123
}
函数预编译:当test执行的前一刻,A0就产生了。
第二步:形参变量都是test
AO{
test:undefined
}
第三步:传参,test = 1
AO{
test:1
}
第四步:函数声明有test
AO{
test:function test() { }
}
函数执行:
第3行:输出test得function test(){ }(当AO里有这个属性值时就拿AO的属性值,没有的话他就会往上找,看看GO里有木有)
第4行: 执行test = 234
AO{
test:234
}
第5行输出test得234,第6行跳过
最后输出结果:function test(test) { console.log(test); var test = 234; console.log(test); function test() { }; } function test() { } 234