用预编译去理解函数声明提高和变量声明提高

在咱们前端笔试的过程当中几乎都会遇到函数声明提高或者变量声明提高的题目,是否是不少人知道这个知识点可是分析的时候仍是会出现不一样程度的错误呢,接下来跟我一步步走下去,让你们之后不再用担忧这类题目带来的困扰。javascript

一、js运行三部曲

咱们必需要了解javascript有2个特色,单线程和解释性语言,能够理解解释性语言是翻译一句执行一句,那么在js运行时是通过如下三步:前端

  • 语法分析java

  • 预编译web

  • 解释执行函数

    说明:语法分析就是通篇扫描一遍是否有语法错误,没有错误进行预编译阶段,而后进行解释执行。
    复制代码

二、预编译前奏

  • imply global 暗示全局变量: 即任何变量,若是变量未经声明就赋值,此变量就为全局对象全部;
  • 一切声明的全局变量,全是window的属性。
eg: 这里只是简要说明下以上亮点。
console.log(window.a) 
console.log(window.b)
function testGlobal(){
    var a = b = 123;
}
testGlobal()
console.log(b)
console.log(a)

eg: 按照咱们思惟解释一行编译一行,没有任何问题。
function test(){
    console.log("test")
}
test()  // test

eg: 按照咱们思惟解释一行编译一行,应该报错呀,为何能正常打印出结果呢。
test1() // test1
function test1(){
    console.log("test1")
}

eg:
var test3 = 5
console.log(test3) // 5

eg: 为何能输出undefined
console.log(test4) //undefined
var test4 = 6

eg: 为啥这样就报错。
console.log(test5) // error

复制代码

通过以上的例子,不少人会快速的总结两句话:ui

  • 1,函数声明总体提高、
  • 2,变量的声明提高。

这2句正确可是不能解决咱们全部问题,很少说,用例子说话:spa

eg: 这里我就不写答案了,本身能够试一试是否掌握。
console.log(a);
function a(a){
    console.log(a);
    var a = 123;
    var a = function(){};
    console.log(a);
}
a(123);
var a = 123;

eg: 这里我就不写答案了,本身能够试一试是否掌握。
console.log(a);
function a(a){
    console.log(a);
    a = 123;
    function a(){};
    console.log(a);
}
a(123);
var a = 123;

复制代码

若是感受有点晕乎,那么咱们了解预编译则能够轻松解答问题。线程

三、预编译

记住预编译发生在函数执行的前一刻,咱们记住如下四部曲便可:翻译

  • 建立AO对象;
  • 找形参和变量声明,将变量和形参做为AO对象的属性名,值为undefined;
  • 将实参值和形参统一;
  • 在函数体里面找到函数声明,值赋予函数体。

那么有人会问了,函数执行是这样,那么全局定义的变量声明和函数声明会是怎样呢,其实同样,不一样的就是第一步,全局建立GO对象,GO也就是等于window。code

eg: 咱们先看函数执行
function fn(a){
    console.log(a);
    console.log(b);
    console.log(c);
    var a = 123;
    function a(){};
    console.log(a);
    var b = function(){};
    console.log(b);
    function c(){};
}
fn(111);

求解:对应以上步骤来
第1步: 建立AO对象
    AO{

    }
第2步:  找形参和变量声明,将变量和形参做为AO对象的属性名,值为undefined,若是形参和变量声明或者函数声明有同名的则写一个就好。
    AO{
        a: undefined,
        b: undefined,
        c: undefined
    }
第3步: 将实参值和形参统一;
    AO{
        a: 111,
        b: undefined,
        c: undefined
    }
第4步: 在函数体里面找到函数声明,值赋予函数体。
    AO{
        a: function a(){},
        b: undefined,
        c: function c(){}
    }

第5步: 在按照顺序执行,提高的和赋值过的咱们就不用看了。
    fn(111);
    console.log(a)       // function a(){} a ==> AO.a
    console.log(b)       // undefined
    console.log(c)       // function c(){}
    a =123               // 这里只剩下赋值 A0.a = 123
    console.log(a)       // 123
    b = function(){};    // AO.b = function(){}
    console.log(b)       // function(){}

复制代码

总结说下第五步,这就是剩下执行的语句了,为啥变量声明和函数声明都没有了呢,就是前面4步已经执行了,这下是否是有点恍然大悟,原来如此简单,咱们继续多来几个例子来讲明,也便于增长记忆。

eg:
function fn1(a,b){
    console.log(a);
    console.log(b);
    var b =234;
    a = 123;
    console.log(a);
    function a(){};
    var a;
    b = 456;
    var b = function(){}
    console.log(a);
    console.log(b);
}
fn1(222);
按照预编译步骤来解:
第1步: 
    AO{} 
第2步: 
    AO{
        a: undefined,
        b: undefined,
    }
第3步: 
    AO{
        a: 222,
        b: undefined,
    }
第4步: 
    AO{
        a: function a(){},
        b: undefined,
    } 
第5步:  解释执行
    fn1(222);
    console.log(a)    // function a(){} 
    cosnole.log(b)    // undefined
    b =  234;         // AO.b = 234
    a = 123           // AO.a = 123
    console.log(a)    // 123
    b = 456;          // AO.b = 456
    b = function(){}  // Ao.b = function(){}
    console.log(a);   // 123
    console.log(b);   // function(){}

复制代码

如今通过以上2个案例是否是基本了解预编译,是否是就不怕函数声明提高和变量声明提高呢,有人说了,要是全局变量声明和有全局函数声明又有函数体内函数声明顺序又是怎么样的呢?

记住全局生成GO对象,函数执行体生成AO对象。其余规则同样,继续来例子说明:

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


第1步: 
    GO{}
第2步:  
    GO{
        global: undefined     
    }  
第3步:, 没有    
第4步:  
    GO{
        global: global(){ ...} 
    }  
第5步:解释执行 
    console.log(global)   // global(){ ...} 
    接下来要执行函数,那么执行函数以前要走4步       
第1步: 
    AO{}

第2步: 
    AO{
        global: undefined
    }
第3步: 没有
第4步: 没有

第5步:解释执行 
    global()
    console.log(global)  // undefined 注意:AO对象找到则值为AO的属性值,没有则去GO对象里面去找
    global = 200         // AO.global = 200
    console.log(global)  // 200
    global = 300         // AO.global = 300
    global = 100;        // GO.global = 100
    console.log(global)  // 100 这里是全局的global

eg: 这一题有了if,其实预编译我只管找你声明,其余无论,那么又和以上步骤相同,还有就是没有声明就赋值则挂在GO对象上
function test(){
    console.log(a);    // undefined AO对象没有,则到GO对象中找
    console.log(b);    // undefined
    if(a){             
        var b = 100;   // 不执行b的赋值
    }
    console.log(b);    // undefined
    c = 234;
    console.log(c)     //234
}
var a ;
test();
a = 10;
console.log(c)  //234

解答,这里我就简要的写最终两个对象的值:
GO{ 
    a: 10
    c: 234
}
AO{
    b: undefined,

}
因此答案很明显.
复制代码

四、总结

通过以上总结,那咱们是否是能够找到规律:

  • 打印变量值前面有赋值,则该值为赋值的值。
  • 打印变量值以前没有赋值,有函数声明则值函数声明,没有再看形参,再没有看变量声明,从AO找到GO。说白了就是4步曲的倒序。

原文网址:weblogger.club/2018/10/19/…

相关文章
相关标签/搜索