浏览器执行JavaScript的过程:
1.语法分析
基本语法检测,有没有基本的语法错误,例如中文标点符号等
2.预编译(预解析)
全局预编译:
① 全局执行代码之前,生成一个GO(Global Object)
②分析变量的声明,var a
如果GO对象上有没有a属性,如果没有,则直接添加a属性,值为undefined
如果GO对象上已经存在a属性,则不做任何操作
③分析函数声明,function fn
如果GO对象已经存在fn属性,直接将整个函数体覆盖,如果不存在就添加fn属性,值为函数体
函数预编译:
①函数运行前的一瞬间,生成Active Object(活动对象),后面简称AO
②函数声明的参数(形参),形成AO对象的属性名,属性值为实参的值,未传递实参则为undefined
③分析变量声明,如 var a
如果AO对象上还没有a属性,则添加AO属性,值为undefined
如果AO对象上已经有a属性,则不做任何影响
④分析函数声明,如 function foo(){}
则把函数赋给foo属性
如果此前foo属性存在,则覆盖
3.逐行执行
浏览器按照预编译分析出来的AO,GO(Global Object分析步骤只是预编译中少了第二个步骤)。逐行执行代码
注:分析过了变量、函数声明的就不用管。后续只需要管赋值即可
预编译(详解):
全局预编译:
1. 生成一个GO对象
2. 分析var关键字声明,如果GO中不存在,则添加,值为undefined,如果存在则忽略
3. 分析function声明,如果存在则覆盖,否则添加
函数预编译
1. 函数运行的一瞬间 ( 定义 运行),生成一个AO(active Object)对象作用域
2. 分析函数的形参,将形参作为AO对象的属性名,值为实参的值,如果没有传递实参,值为undfined
3. 分析var关键字声明,如果AO中不存在,则添加,值为undefined,如果存在则忽略
4. 分析function声明,如果AO中存在则直接覆盖,否则添加
代码解释js预编译:
console.log(num); //undefined(变量提升,值没提升)
var num = 1;//是因为预解析后,相当于执行了以下代码
console.log(num); //1
fn(); //21
function fn(){
console.log(21);
}
//预解析后,相当于执行了以下代码
function fn() { //函数提升
console.log(18);
}
fn();
//这也就解释了声明式函数在调用函数时fn()既可以放在函数的下面,也可以放在函数的上面.
预编译面试题:
第一题:
function test(a,b){
console.log(a);//1
c = 0;
var c;
a = 3;
b = 2;
console.log(b);//2
function b(){}
function c(){}
console.log(b);//2
console.log(c);//0
}
test(1);
第二题:
function fn(a){
console.log(a); //fna
a = 123;
console.log(a); // 123
console.log(a); // 123
b = function(){}
console.log(a); // 123
console.log(b);// fnb
}
fn(1);
第三题:
var b = 3;
console.log(a); //function a(a){}
function a(a){
console.log(a); //function a(){}
var a = 2;
console.log(a); //2
function a(){};
var b = 5;
console.log(b); //5
}
a(1);
第四题:
a = 1;
function test(){
console.log(a); //undefined
a = 2;
console.log(a); //2
var a = 3;
console.log(a); //3
}
test();
var a;
第五题:
a = 1;
function test(e){
function e(){};
arguments[0] = 2;
console.log(e); //2
if(a){ //undefined
var b = 3;
}
var c;
a = 4;
var a;
console.log(b); //undefined
f = 5;
console.log(c); //undefined
console.log(a); //4
}
var a;
test(1);
总结
预编译前奏:生成 GO 对象,有两个规则;
预编译四部曲:
1.创建 AO 对象
2. 找形参和变量声明,将变量和形参名作为 AO 属性名,值为 undefined;
3. 将实参值和形参统一;
4. 在函数体里面找函数声明,值赋予函数体。