JS 预编译
JS 运行三部曲:
- 语法分析
- 预编译
- 解释执行
预编译:
- ** 暗示全局变量 ( imply global ):任何变量,如果未经声明就赋值,该变量即为全局对象 ( window ) 所有**
function test(){
var a = b = 123;//先赋值b为123,声明a,再把b的值赋给a,b未声明就赋值,b为全局变量
}
window.a //undefined
window.b //123
- 一切声明的全局变量,全是 window 的属性
var a = 123;
等价于:
window {
a : 123
}
所以,console.log(a) 是在 window 里寻找 a,即访问的是 console.log(window.a) = 123
function test(){
var a = 123;
}
test();
console.log(window.a);//undefined
预编译发生在函数执行的前一刻:
function fn(a){
console.log(a); //打印 AO 里面的 a : function a(){}
var a = 123; //预编译时 var a 已经提升,这里执行 a =123
console.log(a); //123
function a(){} //预编译时已提升,这里不再执行
console.log(a); //123
var b = function(){} //预编译时 var b 已提升,这里执行 b = function(){}
console.log(b); //function(){}
function d(){}//预编译时已提升
}
fn(1);
具体过程:
1.创建 AO (Activation Object) 对象,即执行期上下文;
AO:{
}
2.找形参和变量声明,将变量和形参名作为 AO 属性名,值为 undefined;
AO:{
a : undefined,
b : undefined
}
3.将实参值和形参统一;
AO:{
a : 1,
b : undefined
}
4.在函数体里面找到函数声明,将函数名作为 AO 对象的属性名,值赋予函数体;
AO:{
a : function a(){},
b : undefined,
d : function d(){}
}
e.g.1
function test(a,b){
console.log(a); // 1
c = 0;
var c;
a = 3;
console.log(a);//3
b = 2;
console.log(b); // 2
function b(){}
function d(){}
console.log(b); //2
}
test(1);
预编译过程:
Step1 省略
Step2:
AO:{
a : undefined,
b : undefined,
c : undefined,
}
Step3:
AO:{
a : 1,
b : undefined,
c : undefined
}
Step4:
AO:{
a : 1,
b : function b(){},
c : undefined,
d : function b(){}
}
e.g.2
function test(a,b){
console.log(a); //functiona(){}一旦有重名的函数声明,必是函数体
console.log(b); //undefined
var b =234;
console.log(b); //234
a = 123;
console.log(a); //123
function a(){}
var a;
b = 234;
var b = function(){};
console.log(a); //123
console.log(b); //function(){}
}
test(1);
预编译过程:
Step2:
AO:{
a : undefined,
b : undefined
}
Step3:
AO:{
a : 1,
b : undefined
}
Step4:
AO:{
a : function a(){},
b : undefined
}
全局的预编译:
1. 生成一个 GO (Global Object) 对象,GO === window;
2. 找形参和变量声明,将变量和形参名作为 AO 属性名,值为 undefined;
3. 在函数体里面找到函数声明,将函数名作为 AO 对象的属性名,值赋予函数体
e.g.3
console.log(a); //undefined
var a =123;
e.g.4
console.log(a); //function a(){}
var a =123;
function a(){}
e.g.5
var a =123;
function a(){}
console.log(a); //123
console.log(window.a); //123
e.g.6
function test(){
var a = b = 123;
console.log(window.b); //123 此时 GO:{b : 123}
console.log(window.a); //undefined 此时AO:{a : undefined}
}
test();
e.g.7
console.log(test);
/*打印函数体 function(test){
console.log(test);
var test = 123;
console.log(test);
function test(){}*/
function test(test){
console.log(test);//function test(){}
var test = 123;
console.log(test); //123
function test(){}
}
test(1);
var test = 234;
全局预编译过程:
GO:{
test: function(test){
console.log(test);
var test = 123;
console.log(test);
function test(){}
}
test1() 执行前:
AO:{
test: function(){}
}
e.g.8
var glob= 100;
function fn(){
console.log(glob);
}
fn();//100
e.g.9
global = 100;
function fn(){
console.log(global); //undefined
global = 200;
console.log(global); //200
var global = 300;
}
fn();
var global;
e.g.10
function test(){
console.log(b); //undefined
if(a) {
var b = 100;
} // a 为undefined,if 不执行
console.log(b); // undefined
c = 234;
console.log(c); //234
}
var a;
test();
a = 10;
console.log(c); //234
e.g.11
function bar(){
return foo; //等价于 console.log(foo);
foo = 10;
function foo(){}
var foo = 11;
}
console.log(bar()); //function foo(){}
e.g.12
console.log(bar()); //11
function bar(){
foo = 10;
function foo(){}
var foo = 11;
return foo;
}