通常预编译被简单概括为函数声明整体提升和变量声明提升
首先回顾函数的常用的两种定义方法
函数声明 function test() { ... } 函数表达式 var test = function() { ... };函数预编译发生在函数执行的前一刻
创建AO对象 Activation Object(执行期上下文)找形参和变量声明,将形参和变量声明作为AO对象属性名,值为undefined将实参的值赋给形参在函数体中找到函数声明,属性名为函数名,属性值为函数体按照四部曲分析
1.创建AO对象 AO { } 2.找形参和变量声明,将形参和变量声明作为AO对象属性名,值为undefined AO { a: undefined, b: undefined, c: undefined } 3.将实参的值赋给形参 AO { a: 1, b: undefined, c: undefined } 4.在函数体中找到函数声明,属性名为函数名,属性值为函数体 AO { a: 1, b: function b() {}, c: undefined, d: function d() {} }接下来按顺序执行语句
function test(a, b) { console.log(a); //1 console.log(b); //function b c = 0; a = 3; b = 2; console.log(b); //2 } test(1);全局预编译与函数预编译差别不大,发生在执行全局前
创建GO对象:执行期上下文(Global Object)寻找变量声明,并且当做属性放在GO对象里,值为undefined寻找函数声明,值赋予函数体执行全局前,开始全局预编译
1. 创建GO对象 GO { } 2. 寻找变量声明,并且当做属性放在GO对象里,值为undefined GO { test: undefined、 } 3. 寻找函数声明,值赋予函数体 GO { test: function test(test) { ... } }执行语句
console.log(test);// function test(test) {...} function test(test) { console.log(test); var test = 234; console.log(test); function test () { } } test(1); test = 123;执行函数前发生函数预编译
1.创建AO对象 AO { } 2.找形参和变量声明,将形参和变量声明作为AO对象属性名,值为undefined AO { test: undefined } 3.将实参的值赋给形参 AO { test: 1 } 4.在函数体中找到函数声明,属性名为函数名,属性值为函数体 AO { test: function test () {} }执行函数
function test(test) { console.log(test); // function test () {} test = 234; console.log(test); // 234 function test () { } }分析
//GO { // bar : function bar() {}, //} function bar() { return foo; foo = 10; function foo() { } var foo = 11; } //AO { // foo: undefined => function foo() {}, //} console.log(bar());//function foo() {}分析
//GO { // bar: function bar() {}, //} //AO { // foo: undefined => function foo(){} => 10 => 11 //} console.log(bar()); //11 function bar() { foo = 10; function foo() { } var foo = 11; return foo; }