javascript之變數提升與函式提升

minghu發表於2018-11-05

前言

從概念的字面意義上說,"變數提升”意味著變數和函式的宣告會在物理層面移動到程式碼的最前面,但這麼說並不準確。實際上變數和函式宣告在程式碼裡的位置是不會動的,而是在編譯階段被放入記憶體中。


不多說,直接擼程式碼吧 ~~~///(^v^)\\\~~~

正文

什麼是變數提升?

javascript在被解析的時候,會有一個預解析階段,這個時候解析器會將當前上下文環境中的所有變數(不包括es6中的let和const宣告)和函式宣告提升到最前面。

先來看下面的程式碼:

    'use strict';
    
    console.log(a); // undefined
    var a = 1;
    console.log(a); // 1
複製程式碼

那麼在程式碼被解析的時候,就是這樣:

    'use strict';
    
    var a;
    
    console.log(a); // undefined
    
    a = 1;
    
    console.log(a); // 1
複製程式碼

那麼這個過程就很好理解了。

但是如果有多個同名變數呢?

同名變數宣告

同一作用域下,對於同名變數宣告,採用的是忽略原則,後宣告的會被忽略,變數的賦值,會採取覆蓋原則。

  • 同一作用域下同名變數宣告

看如下程式碼:

    'use strict';
    
    console.log(a); // undefined
    
    var a = 1;
    
    console.log(a); // 1
    
    var a = 2;
    
    console.log(a); // 2
複製程式碼

解析後的程式碼如下:

    'use strict';
    
    var a;
    
    console.log(a); //undefined
    
    a = 1;
    
    console.log(a); // 1
    
    a = 2;
    
    console.log(a); // 2
複製程式碼
  • 不同作用域下同名變數宣告

程式碼如下:

    'use strict';
    
    console.log(a); // undefined
    
    var a = 1;
    
    function b() {
    
        console.log(a); // undefined
        
        var a = 2;
        
        console.log(a); // 2
    };
    
    b();
複製程式碼

解析後的程式碼如下(此處涉及到的執行上下文環境和作用域會另有文章詳細說明):

  1. 首先進入全域性上下文環境,此時程式碼解析如下:

    'use strict';
    
    function b() {
        console.log(a);
        var a = 2;
        console.log(a);
    };
    
    var a;
    
    console.log(a); // undefined
    
    a = 1;
    
    b();
複製程式碼

  2. 當執行到呼叫b函式的時候,進入b函式的上下文環境,b函式的程式碼被解析時,如下:

    var a;
    
    console.log(a); // undefined
    
    a = 2;
    
    console.log(a); 2
複製程式碼

在不同作用域中,就近原則,如果在當前作用域中找到,則不再向上一級作用域查詢,如果沒找到,則會找上一級作用域,一直找到全域性作用域。

所以下面只討論同一作用域下的情況。

同名函式宣告

同一作用域下,對於同名函式宣告,採用的是覆蓋原則,先宣告的會被覆蓋。

程式碼如下:

    'use strict';
        
    console.log(a); // function a() { console.log(2) }
    
    function a() {
        console.log(1);
    };
    
    function a() {
        console.log(2);
    };
    
    console.log(a); // function a() { console.log(2) }
複製程式碼

解析後的程式碼如下:

    'use strict';
    
    function a() {
        console.log(2);
    };
    
    console.log(a); // function a() { console.log(2) }
    
    console.log(a); // function a() { console.log(2) }
複製程式碼

同一作用域下,同名的函式宣告和變數宣告

對於同名的函式宣告和變數宣告,採用的是忽略原則,函式宣告會提升到變數宣告之前,變數宣告會被忽略,函式宣告有效。

程式碼如下:

    'use strict';
    
    console.log(a); // function a() {}
    
    var a;
    
    function a() {};
複製程式碼

解析後的程式碼如下:

    'use strict';
    
    function a() {};
    
    console.log(a); // function a() {}
複製程式碼

如果存在賦值操作,就會採取覆蓋原則。
看如下程式碼:

    'use strict';
    
    console.log(a); // function a() {}
    
    var a = 1;
    
    function a() {};
    
    console.log(a); // 1
複製程式碼

解析後的程式碼如下:

    'use strict';
    
    function a() {};
    
    console.log(a); // function a() {}
    
    a = 1;
    
    console.log(a); // 1
複製程式碼

總結

  • 同一作用域下,對於同名變數宣告,採用的是忽略原則,後宣告的會被忽略,變數的賦值,會採取覆蓋原則。
  • 同一作用域下,對於同名函式宣告,採用的是覆蓋原則,先宣告的會被覆蓋。
  • 同一作用域下,對於同名的函式宣告和變數宣告,採用的是忽略原則,函式宣告會提升到變數宣告之前,變數宣告會被忽略,函式宣告有效。

如果有遺漏或者不對的地方,還請指正,先謝過~~~///(^v^)~~

相關文章