🔥JavaScript做用域和變量提高,你真的會了麼?(下)

image.png


這是我參與8月更文挑戰的第12天,活動詳情查看:8月更文挑戰javascript


說明:文章部份內容及圖片出自網絡,若有侵權請與我本人聯繫(主頁有公衆號:小攻城獅學前端)前端

做者:小隻前端攻城獅、 主頁:小隻前端攻城獅的主頁、 來源:掘金java

GitHub:P-J27、 CSDN:PJ想作前端攻城獅git

著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。github


全局做用域

直接編寫在script標籤中的JS代碼,都在全局做用域。web

  • 全局做用域在頁面打開時建立,在頁面關閉時銷燬編程

  • 在全局做用域中有一個全局對象window,它表明的是一個瀏覽器的窗口,由瀏覽器建立,咱們能夠直接使用。瀏覽器

在全局做用域中:markdown

  • 建立的變量都會做爲window對象的屬性保存。好比在全局做用域內寫 var a = 100,這裏的 a 等價於 window.a
  • 建立的函數都會做爲window對象的方法保存。

變量的聲明提早(變量提高)

使用var關鍵字聲明的變量( 好比 var a = 1),會在全部的代碼執行以前被聲明(可是不會賦值),可是若是聲明變量時不是用var關鍵字(好比直接寫a = 1),則變量不會被聲明提早。網絡

舉例1

console.log(a);
    var a = 123;
複製代碼

打印結果:undefined。注意,打印結果並無報錯,而是 undefined,說明變量 a 被提早聲明瞭,只是還沒有被賦值。

舉例2

console.log(a);
    a = 123;   //此時a至關於window.a
複製代碼

程序會報錯:Uncaught ReferenceError: a is not defined

舉例3

a = 123;   //此時a至關於window.a
    console.log(a);
複製代碼

打印結果:123。

舉例4

foo();
function foo() {
    if (false) {
        var i = 123;
    }
    console.log(i);
}
複製代碼

打印結果:undefined。注意,打印結果並無報錯,而是 undefined。這個例子,再次說明了:變量 i 在函數執行前,就被提早聲明瞭,只是還沒有被賦值。

例4中, if(false)裏面的代碼雖然不會被執行,可是整個代碼有解析的環節,解析的時候就已經把 變量 i 給提早聲明瞭。

總結

既然JS中存在變量提高的現象,那麼,在實戰開發中,爲了不出錯,建議先聲明一個變量,而後再使用這個變量。


函數的聲明提早

函數聲明

使用函數聲明的形式建立的函數function foo(){}會被聲明提早。上面例四就是這個案例。

也就是說,整個函數會在全部的代碼執行以前就被建立完成。因此,在代碼順序裏,咱們能夠先調用函數,再定義函數。

代碼舉例:

fn1();  // 雖然 函數 fn1 的定義是在後面,可是由於被提早聲明瞭, 因此此處能夠調用函數

    function fn1() {
        console.log('我是函數 fn1');
    }

複製代碼

函數表達式

使用函數表達式建立的函數var foo = function(){}不會被聲明提早,因此不能在聲明前調用。

很好理解,由於此時foo被聲明瞭(這裏只是變量聲明),且爲undefined,並無把 function(){} 賦值給 foo。

因此說,下面的例子,會報錯:


函數做用域

提醒1:在函數做用域中,也有聲明提早的特性:

  • 函數中,使用var關鍵字聲明的變量,會在函數中全部的代碼執行以前被聲明。

  • 函數中,沒有var聲明的變量都是全局變量,並且並不會提早聲明。

舉例:

var a = 1;

    function foo() {
        console.log(a);
        a = 2;     // 此處的a至關於window.a
    }

    foo();
    console.log(a);   //打印結果是2

複製代碼

上方代碼中,執行foo()後,函數裏面的打印結果是1。若是去掉第一行代碼,執行foo()後,函數裏面的打印結果是Uncaught ReferenceError: a is not defined。 a=2雖然是全局變量,可是不存在變量提高,不能前後聲明。

提醒2:定義形參就至關於在函數做用域中聲明瞭變量。

function fun6(e) { // 這個函數中,由於有了形參 e,此時就至關於在函數內部的第一行代碼裏,寫了 var e;
        console.log(e);
    }

    fun6();  //打印結果爲 undefined
    fun6(123);//打印結果爲123
複製代碼

JavaScript 沒有塊級做用域(ES6以前)

在其餘編程語言中(如 Java、C#等),存在塊級做用域,由{}包括起來。好比在 Java 語言中,if 語句裏建立的變量,只能在if語句內部使用:

if(true){
    int num = 123;
    system.out.print(num); // 123
}
system.out.print(num); // 報錯
複製代碼

可是,在 JS 中沒有塊級做用域(ES6以前)。舉例以下:

if(true){
var num = 123;
    console.log(123); //123
}

console.log(123); //123(能夠正常打印)

複製代碼

做用域鏈

引入:

  • 只要是代碼,就至少有一個做用域

  • 寫在函數內部的局部做用域

  • 若是函數中還有函數,那麼在這個做用域中就又能夠誕生一個做用域

基於上面幾條內容,咱們能夠得出做用域鏈的概念。

做用域鏈:內部函數訪問外部函數的變量,採用的是鏈式查找的方式來決定取哪一個值,這種結構稱之爲做用域鏈。查找時,採用的是就近原則

代碼舉例:

var num = 10;

function fn() {
    // 外部函數
    var num = 20;

    function fun() {
        // 內部函數
        console.log(num);
    }
    fun();
}
fn();

複製代碼

打印結果:20。

關於更多做用域和做用域鏈的問題能夠看這篇文章,直接點我。


感謝閱讀,但願能對你有所幫助,文章如有錯誤或者侵權,能夠在評論區留言或在個人主頁添加公衆號聯繫我。

寫做不易,若是以爲不錯,能夠「點贊」+「評論」 謝謝支持❤

相關文章
相關標籤/搜索