js预编译(与C预处理区别)

目录

1.函数体内

2.全局

注:window 属性和  imply global属性

3.全局和函数体内结合,优先顺序

例1:

例2:

例3(重要提示)


第一次学的时候以为和C预处理差不多,看了下才发现区别还蛮大的;

例1:

test();//打印出 a
function test(){
    console.log("a");
}

例2:

console.log(a); //打印undefined
var a = 10;
console.log(a); //直接报错

这里可以发现,跟C预处理不一样,js的预编译会先把全局变量先声明,所以才会有undefined;而C的预处理包括

  1.  宏定义指令(#define删除);
  2. 条件编译指令:处理所有的条件预编译指令。
  3. 头文件包含指令:处理#include 预编译指令。
  4. 特殊符号指令(比如注释符号)
  5. 等等

跟js差别蛮大的,我们这里来看预编译的例子。

1.函数体内

如下:

function fn(a){
    console.log(a);
    
    var a = 123;

    console.log(a);

    function a(){}

    console.log(a);

    var b = function(){}

    console.log(b);

    function d(){}
}
fn(1);

这里存在以a为名的变量,函数,赋值等操作,如果不懂预编译,可能会直接懵了,我们需要看预编译的顺序:

首先预编译发生在函数执行前一刻,一共四步:

  1. 创建AO对象Activation Object(执行期上下文);
  2. 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined;
  3. 将实参值和形参统一;
  4. 在函数体中找函数声明,值赋予函数体;

所以我们可以把这个例子过一遍

1.首先创建AO对象

AO{

}

2.找形参和变量声明,将变量和形参名作为AO属性名,值为undefined

AO{
    a:undefined
    b:undefined
}

3.将实参值和形参统一

AO{
    a:1
    b:undefined
}

4.在函数体中找函数声明,值赋予函数体

AO{
    a:function(){}
    b:undefined //var b = function(){}不是函数声明,是赋值
    d:function(){}
}

四步完后,创建完AO对象,执行函数 fn(a),

  1. 执行第一句 console.log(a);AO对象的 a 为 function(){},即打印 function(){};
  2. 执行第二句,因为var已经在预编译处理过,所以变量声明不看,但是 a = 123没有走过,所以 a 赋值为123;AO里 a = 123;
  3. 执行第三句,a已经赋值为123,所以打印123;
  4. 执行第四句,function a(){} 在预编译已经处理过,所以不看,a 仍为123;
  5. 执行第五句,继续打印123;
  6. 执行第六句,function b 不看,已经执行过了。所以执行 b = function(){};AO里 b = function(){};
  7. 执行第七句,打印机 function (){};
  8. 执行第八句,预编译处理过,不处理跳过;

所以结果为:

ƒ a(){}
123
123
ƒ (){}

 

2.全局

全局预编译和函数体内大致相同,但全局没有形参实参,所以省略第三步

  1. 创建GO对象Global Object(执行期上下文);
  2. 找变量声明,将变量作为AO属性名,值为undefined;
  3. 在函数体中找函数声明,值赋予函数体;

 

注:window 属性和  imply global属性

1.任何全局变量都是 window 的属性,我们可以这么调用

console.log(window.a); //打印 a(){},跟写console.log(a)结果相同
function a(){}

所以这里的 GO实际上跟 window是一样的。

2.所有未经声明就赋值的变量都在 imply global 属性中,实际上也就是在 GO中

例如:

function test(){
    var a = b = 123;
    console.log(window.a); //undefined
    console.log(window.b); //打印123
}
test();
//生成 AO 对象,AO对象中含有 a,而 b 因为没有声明,属于 GO 对象

 

3.全局和函数体内结合,优先顺序

例1:

console.log(test);
function test(test){
    console.log(test);
    var test = 234;
    console.log(test);
    function test(){};
}
test(1);
var test = 123;

预编译顺序:

1.首先找全局变量

GO{
    test:undefined   
}

2.找函数声明

GO{
    function test(){ ... }   
}

3.开始执行,console.log(test),即打印function(){...}

4.function test 在预编译已经声明了,所以跳过,走到 test(1) 这一句,开始执行,生成 AO;

AO{

    //test:undefined; 这句最后被 实参1 覆盖

    //test:1; 这句最后被 function(){}覆盖

    test:function(){}

}

5.所以走到函数内第一句console.log(test),打印 function(){}

6.后面的几句跟上述相同,赋值,打印234,跳过函数声明;

:如果AO上没有要打印的变量,去GO继续找;

 

例2:

global = 100;
function fn(){
    console.log(global);
    global = 200;
    console.log(global);
    var global = 300;
}
fn();
var global;

首先预编译,找变量声明,var global放入 GO 对象,然后继续放入 fn函数;

然后执行程序,GO中 global = 100,执行 fn();

进入函数后,进行预编译,生成 AO对象,加入 var global ,所以第一个打印是 undefined;(先 AO没有的话,再是GO)

后面那个打印即200;

 

例3(重要提示)

function test(){
    console.log(b);
    if(a){
        var b = 100;
    }
    console.log(b);
    c = 234;
    console.log(c);
}
var a;
test();
a = 10;
console.log(c);

这里 GO 和 AO 的执行顺序按照之前写的一样,遇到 if 或者其他比如 for等等,都不需要管,直接拿出变量声明即可;

所以这里的执行顺序,

  1. GO对象,加入 var a,加入 function test();
  2. 运行程序,在 test() 进入函数,然后创建 AO 对象;
  3. AO 对象 加入 变量声明 var b;所以打印 undefined
  4. 然后执行程序;由于 a 还是 undefined,所以 if 不执行,打印 undefined
  5. c = 234,未声明变量赋值,所以在 GO 中加入,打印 c 的时候,AO中没有,但是 GO 中存在,打印234
  6. 然后跳出函数,console.log(c),由于 c 在 GO 中,所以打印234

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值