我们都知道js执行遵循两个规则
1.函数声明整体提升
2.变量 声明提升
其实还有一点最重要的就是预编译,预编译往往发生在函数执行前,了解预编译,对我们理解函数执行非常关键。
预编译的前奏
1.imply global暗示全局变量:即任何变量,如果变量未经声明就赋值,此变量就为全局属性所有。
2.一切声明的全局变量,全是window的属性。
下面就先看几个例子吧
例1 function fn(a){
console.log(a);
var a = 123;
console.log(a);
function a(){};
console.log(a);
var b = function(){};//这是函数表达式,不是函数声明(var b属于变量声明)
console.log(b);
function d(){}
}
fn(1);
1.创建AO对象
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(){};
}
全部执行后
AO{
a:123;
b : function (){};
d : function d(){};
}
函数执行结果
function fn(a){
console.log(a); //function a(){}
var a = 123;
console.log(a); //123
function a(){};
console.log(a); //123
var b = function(){};//这是函数表达式,不是函数声明(var b属于变量声明)
console.log(b); // function (){};
function d(){}
}
fn(1);
例2 function test(a,b){
console.log(a);
c = 0;
var c;
a = 3;
b = 2;
console.log(b);
function b(){};
function d(){};
console.log(b);
}
test(1);
1.创建AO对象
AO{
}
2.查找函数内的形参和变量声明,并将形参和变量声明作为AO对象的值,值为undefined
AO{
a : undefined;
b : undefined;
c : undefined;
}
3.形参实参相统一,实参的值赋给形参
AO{
a : 1;
b : undefined;
c : undefined;
}
4.查找函数声明,函数名为AO对象的属性,值为函数体
AO{
a : 1;
b : function b(){};
c : undefined;
d : function d(){}
}
全部执行后
AO{
a:1->3;
b : 2;
c : 0;
d : function d(){};
}
函数执行结果
function test(a,b){
console.log(a);//1
c = 0;
var c;
a = 3;
b = 2;
console.log(b);//2
function b(){};
function d(){};
console.log(b);//2
}
test(1);
例3 function test(a,b){
console.log(a);
console.log(b);
var b =234;
console.log(b);
a=123;
console.log(a);
function a(){};
var a;
b = 234;
var b = function(){}
console.log(a);
console.log(b);
}
test(1);
1. 创建AO对象
AO{
}
2.查找函数形参和函数内的变量声明,形参名和函数名作为AO对象的属性,值为undefined
AO{
a : undefined;
b : undefined;
}
3.将形参和实参相统一,实参值赋给形参
AO{
a : 1;
b : undefined;
}
4. 查找函数声明,函数名作为AO对象的属性,值为函数体
AO{
a : function a(){};
b : undefined;
}
执行结果
function test(a,b){
console.log(a); //function a(){}
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);
预编译不只发生在函数里,还发生在全局里,这时候回身构成一个GO(Global Object //window Object)
例4
console.log(test);
function test(test){
console.log(test);
var test =234;
console.log(test);
function test(){
}
}
test(1);
var test= 123;
1.先创建一个GO
GO{
}
2.查找全局的变量声明
GO{
test : undefined;
}
4.查找函数声明
GO{
test : function test(test){
console.log(test);
var test =234;
console.log(test);
function test(){
}
}
}
1.先创建一个AO
AO{
}
2.查找函数形参和函数内的变量声明,形参名和函数名作为AO对象的属性,值为undefined
AO{
test : undefined;
}
3.将形参和实参相统一,实参值赋给形参
AO{
test : 1;
}
4. 查找函数声明,函数名作为AO对象的属性,值为函数体
AO{
test : function test(){
};
}
例5
global = 100;
function fn(){
console.log(global);
global = 200;
console.log(global);
var global = 300;
}
fn();
var global;
1.GO{
global : 100;
}
2.AO{
global : undefined;
}
执行结果
global = 100;
function fn(){
console.log(global); //undefined
global = 200;
console.log(global); //200
var global = 300;
}
fn();
var global;
例6
function test(){
console.log(b);
if(a){
var b = 180;
}
c = 234;
console.log(c)
}
var a;
test();
a = 10;
console.log(c);
1.GO{
a : undefined;
test :function test(){
console.log(b);
if(a){
var b = 180;
}
c = 234;
console.log(c)
}
}
2.AO{
B:undefined;
}
执行结果
function test(){
console.log(b); //undefined
if(a){
var b = 180;
}
c = 234;
console.log(c); //234
}
var a;
test();
a = 10;
重要的事,说多少遍都不算多哈,最后总结:
预编译(函数执行前)※
1. 创建AO对象(Active Object -- 执行上下文)
2. 查找函数形参及函数内变量声明,形参名及变量名作为AO对象的属性,值为undefined
3. 实参形参相统一,实参值赋给形参
4. 查找函数声明,函数名作为AO对象的属性,值为函数引用
预编译(脚本代码块script执行前)
1. 查找全局变量声明(包括隐式全局变量声明,省略var声明),变量名作全局对象的属性,值为undefined
3. 查找函数声明,函数名作为全局对象的属性,值为函数引用