JS 预编译过程分析

JS运行三部曲

  • 语法分析
  • 预编译
  • 解释执行

预编译要记住两点

1.函数声明整体提升
只要写一个函数声明 系统就会把该函数声明提到逻辑的最前面 无论在哪里调用 都是在函数声明后调用

    //函数声明整体提升
    test();//放在函数体的前面也可以执行
    function test(){
        document.write('a');
    }
    test();

输出aa

2.变量声明提升
var a=123;//这是变量的声明(var a;)+赋值(a=123;)
所以只会把var a;(变量的声明)提到前面

//变量 声明提升
    document.write(a);
    var a=123;
    document.write(a);

输出undefineda


注意:

window就是全局的域
1.imply global暗示全局变量:即任何变量,如果变量未经声明就赋值,此变量就为全局变量window所有

 a=123;-->window.a=123;

2.一切声明的全局变量(函数里声明的是局部变量),全是window的属性

 var a=123;--> window.a=123;
 console.log(a);-->console.log(window.a);
 function test1(){
        /*赋值语句执行顺序 从右向左赋值
        * 先将123赋值给b(b在这里未经声明 归window所有)
        * 再声明a
        * 再将b的值赋给a
        * */
        var a=b=123;
        //console.log(a);123
        //console.log(window.a);undefined
        //console.log(b);123
        //-->console.log(window.b);123
    }
    test1();

预编的过程(按顺序执行)

  1. 函数内的预编译:

    (1.创建AO对象(Activation Object活动对象/执行期上下文)(函数产生的存储空间库)

    (2.找形参和变量声明(变量声明不考虑逻辑 只要是声明就行)(变量声明提升),将变量名和形参名作为AO属性名,值为undefined

    (3.将实参值和形参统一(给形参赋传递过来的相对应的实参的值)

    (4.在函数体里面找函数声明(函数声明整体提升),其值就是函数体

便于理解的范例:


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);

函数内的预编译发生在函数执行的前一刻,函数内的预编译过程如下:

1.创建AO对象

AO{}

2.找形参和变量声明(变量声明不考虑逻辑 只要是声明就行)(变量声明提升),将变量名和形参名作为AO属性名,值为undefined

AO{

//形参
a:undefined,

//变量声明 a已经存在则不写
b:undefined

}

3.将实参值和形参统一(给形参赋传递过来的相对应的实参的值)

AO{

//形参a 和 调用函数传递的实参1统一
a:1,

b:undefined

}

4.在函数体里面找函数声明(函数声明整体提升),值赋予函数体

AO{

//有a的函数声明 将ade函数声明的值(函数体)赋给变量a
a:function a(){},

// var b=function(){}不是函数声明 而是函数表达式 不提升
b:undefined,

d:function d(){}

}

预编译完成,函数执行(解释性语言 一行一行执行)


function fn(a){
//依照AO对象里的变量 a此时是函数体 打印出function a(){}
       console.log(a);
//预编译第二步 变量声明提升 var a;已经优先执行  这里只需执行a=123;的赋值方法,此时AO对象里的a变量的值变为123
       var a=123; 
//依照AO对象里的变量 a此时是123
       console.log(a);
//预编译第四步 函数声明整体提升 该语句已经优先执行 跳过
       function a(){}
//依照AO对象里的变量 a此时是123
       console.log(a);
//预编译第二步 变量声明提升 var b;已经优先执行  这里只需执行b=function(){}的赋值方法,此时AO对象里的b变量的值变为function(){}
       var b=function(){}
//依照AO对象里的变量 b此时是function(){}
       console.log(b);
//预编译第四步 函数声明整体提升 该语句已经优先执行 跳过
       function d(){}
   }
    //函数预编译发生在函数执行的前一刻
   fn(1);

执行完后的AO对象:
AO{

a:123,
b:function (){},
d:function d(){}

}

  1. 全局预编译(跟函数内预编译差不多):
    (1.生成一个GO对象(Global Object)也就是window对象

    (2.找变量声明(变量声明不考虑逻辑 只要是声明就行)(变量声明提升),将变量名作为GO属性名,值为undefined

    (3.找函数声明(函数声明整体提升),值赋予函数体

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

全局预编译发生在全局要执行的前一刻,全局预编译过程如下:
1.生成一个GO对象(Global Object)也就是window对象

GO{}

2.找变量声明(变量声明不考虑逻辑 只要是声明就行)(变量声明提升),将变量名作为GO属性名,值为undefined

GO{

a:undefined

}

3.找函数声明(函数声明整体提升),值就是函数体

GO{

a:function a(){}

}

预编译完,程序执行:

//预编译第二步 变量声明提升 var a;已经优先执行  这里只需执行a=123;的赋值方法,此时GO对象里的a变量的值变为123
var a=123;
//预编译第三步 函数声明整体提升 该语句已经优先执行 跳过
function a(){}
//依照GO对象里的变量 a此时是123
console.log(a);
//GO就是window 就是一个对象的两个名字
console.log(window.a);
  1. 全局预编译和函数内预编译同时存在时,先执行全局预编译生成GO对象:
    例题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对象(Global Object)就是window对象

GO{}

2.找变量声明(变量声明不考虑逻辑 只要是声明就行)(变量声明提升),将变量名作为GO属性名,值为undefined

GO{

test:undefined

}
3.找函数声明(函数声明整体提升),值就是函数体

GO{

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

}
4.全局预编译完 程序开始执行

依照GO对象里的变量 test此时是函数体
console.log(test);
//预编译第三步 函数声明整体提升 该语句已经优先执行 跳过
function test(test){
       console.log(test);
       var test=234;
       console.log(test);
       function test(){}
}
//函数预编译发生在函数执行的前一刻  生成AO对象
test(1);
var test=123;

5.创建AO对象

AO{}

6.找函数内的形参和变量声明(变量声明不考虑逻辑 只要是声明就行)(变量声明提升),将变量名和形参名作为AO属性名,值为undefined

AO{

//形参
test:undefined

}

7.将实参值和形参统一

AO{

//形参a 和 调用函数传递的实参1统一
test:1

}

8.在函数体里面找函数声明(函数声明整体提升),值赋予函数体

AO{

//有a的函数声明 将a的函数声明的值(函数体)赋给变量a
test:function (){}

}

预编译完成,函数执行(解释性语言 一行一行)

function test(test){
//依照AO对象里的变量 test此时是函数体  AO GO里都有test 采用就近原则
       console.log(test);
//变量声明已经优先执行 这里只执行test=234
       var test=234;
//依照AO对象里的变量 test此时是234
       console.log(test);
//函数声明已经优先执行 跳过
       function test(){}
}

函数执行完成,程序继续执行

依照GO对象里的变量 test此时是函数体
console.log(test);
//预编译第三步 函数声明整体提升 该语句已经优先执行 跳过
function test(test){
       console.log(test);
       var test=234;
       console.log(test);
       function test(){}
}
//函数预编译发生在函数执行的前一刻  生成AO对象
test(1);
//test函数执行完成 
//变量声明已经优先执行 这里只执行test=123 这里的test是GO里的test
var test=123;

程序执行完成后
GO{

test:123

}
例题2:

 	a = 100;
    function demo(e) {
        function e() {}
        arguments[0] = 2;
        console.log(e);
        if (a) {
            var b = 123;
            function c() {
            }
        }
        var c;
        a = 10;
        var a;
        console.log(b);
        f = 123;
        console.log(c);
        console.log(a);
    }
    var a;
    demo(1);
    console.log(a);
    console.log(f);

直接写了哈

1.全局预编译
GO{

a:undefined,
demo:function(){...}

}

2.全局预编译完 程序执行

 a = 100;

GO{

a:100,
demo:function(){...}

}

 demo(1);//执行函数

3.函数内预编译和执行

 function demo(e) {
        function e() {}
        //实参列表和形参有映射 arguments[0]-->e 故给AO对象里的e变量赋值2
        arguments[0] = 2;
        //此时AO对象里的e的值为2
        console.log(e);
        //此时AO对象里的a的值为undefined if语句不执行
        if (a) {
            var b = 123;
            function c() {}
        }
        var c;
        a = 10;
        var a;
        //此时AO对象里的b的值为undefined
        console.log(b);
        //AO对象里没有f变量的声明 故f定义在GO对象里
        f = 123;
        //此时AO对象里的c的值为undefined
        console.log(c);
        //此时AO对象里的a的值为10
        console.log(a);
    }

AO{

//形参1->函数体->arguments[0]映射的2
e:2,
//以下是声明的变量
b:undefined,
c:undefined,(if语句里本不能定义函数,这是个小错误)
a:10

}

GO{

a:100,
demo:function(){...},
f:123

}
4.函数执行结束 程序继续执行

    //此时GO对象里的a的值为100
    console.log(a);
    //此时GO对象里的f的值为123
    console.log(f);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值