深入理解JavaScript的函數作用域

什麼是作用域 ?

作用域:一個變量可以生效的範圍。
變量不是在所有地方都可以使用的,而這個變量的使用範圍就是我們要說的作用域。

注意:在JavaScript中,劃分作用域也是用大括號劃分的, 但是在 JS 之中能夠有效限定作用域的大括號只有函數大括號!

有哪些作用域 ?

- 全局作用域(不再任何函數內)

學習使用作用域,以下內容是所需要了解的:

  • 全局作用域是最大的作用域
  • 在全局作用域中定義的變量可以在任何地方使用
  • 頁面打開的時候,瀏覽器會自動給我們生成一個全局作用域 window
  • 這個全局作用域會一直存在,直到頁面關閉纔會銷燬

請看下面示例代碼:

    var a = 10;
    console.log(a);  // 輸出結果: 10
    function foo(){
        console.log(a);  // 輸出結果: 10
    }
	foo()

當變量 a 聲明時,沒有被函數大括號包裹, 那麼這個變量我們稱之爲 全局變量

這個全局變量在任何地方都可以訪問。

- 局部作用域(在函數內部)

同樣的,以下內容也是所需要了解的:

  • 局部作用域就是在全局作用域下面開闢出來的一個相對小一些的作用域
  • 在局部作用域中定義的變量只能在這個局部作用域內部使用
  • 在 JS 中只有函數能生成一個局部作用域,別的都不行
  • 每一個函數,都是一個局部作用域

請看下面示例代碼:

    function foo(){
        var a = 10; //在大括號之中聲明的變量只能在這個大括號之中使用;
        console.log(a); // 輸出結果: 10
    }
    foo();
    console.log(a); // 報錯 => ReferenceError: a is not defined

通過上面示例代碼可以看出:

在函數大括號之中聲明的變量,這種變量我們稱之爲 局部變量

局部變量只能在聲明它的作用域之中使用;

我們見慣了常規情況,現在看一個特殊情況:

聲明變量時不使用 var 關鍵字聲明:

注意!這是一個不規範的聲明方式!不要使用!不要使用!不用使用!

使用之後導致的結果就是:一個局部變量的聲明,在全局中也可以被訪問了!( 這樣的聲明叫做 僞全局變量

請看下面示例代碼:

    function foo(){
        a = 10; // 此時聲明變量 a 沒有使用var關鍵字聲明
        console.log(a); // 輸出結果:10
    }
    foo();
    console.log(a); // 不報錯了,輸出結果:10;

看完上面的代碼示例,你是不是覺得這不挺好的嘛,變量 a 可以隨便使用,都不用報錯了,爲什麼不讓使用??

呵呵,別高興太早,繼續往下看,你的這個想法很危險的!

當把局部變量變成僞全局變量:

你會發現:

  1. 生命週期變長,造成一定的負面影響;
  2. 佔據了全局命名空間,造成不可預知的錯誤

在這裏插入圖片描述

是不是腦子裏突然蹦出了好多問題:生命週期是什麼鬼?命名空間又是什麼鬼??

好吧,上面這個內容我說早了,那麼接着往下看:

全局變量和局部變量的區別:

在這裏就來聊一下上面的生命週期和命名空間吧!

生命週期(這個變量在內存之中存活的時間)

就是你啥時候可以訪問!

- 全局變量:生命週期是和程序同步的, 程序不關閉,變量就一直存在;

導致的結果就是會讓程序變得更重! 如果可能,還是少設計一點全局變量吧!對大家都好

- 局部變量:生命週期是和函數執行同步的,函數執行結束變量就被刪除了;

現在知道啥是生命週期了吧,全局變量多了,可能真的會影響到我們程序的運行效率,上面說的僞全局變量就是這個道理。

我們看完了生命週期,再來一起看一下命名空間吧!

命名空間(變量名命名的唯一性)

- 全局變量:命名空間是唯一的,一個頁面只有一個

我們先來舉一個小例子,話不多說上代碼:

    var count = 10;
    function foo(){
        // 我的代碼 : 我的私人領域;
        // 程序的懶惰原則:函數的大括號之中如果已經有了查找結果,那麼就不會繼續再查找了;
        // 就近原則;
        var count = 0;
        console.log(count);  // 運行結果:0
    }
    foo();
    console.log(count);  // 運行結果:10

爲了解決全局之中的命名空間是唯一的這個問題,我們可以把這個變量放在局部,那麼就不會佔用全局的命名空間了。

- 局部變量:命名空間一個作用域一個

可以用匿名函數來解決命名空間的問題

最後一個問題:我現在要寫一大坨代碼,和別人的代碼要配合 。
這個時候咋寫呢???

我可以把代碼寫在一個沒有名字的函數之中!
什麼?這樣寫直接報錯 ?
JS 爲啥阻止他 ? 如果我立即調用呢!來一個瞞天過海如何?

讓匿名函數經歷一次運算: 如果函數發生了特定的運算, 那麼這個函數就會被當做一個地址;

    // 讓匿名函數經歷一次運算:  如果函數發生了特定的運算,那麼這個函數就會被當做一個地址;
    // var res = 1 + function(){} 
    // console.log(res); //運行結果:1function(){}
    
    // 利用這個機制使用匿名函數立即調用 : 
    // +function(){
    //     console.log("hello world")
    // }();
    
    // 函數經過運算變成了地址,被後面的調用運算符調用了;
    // !function(){
    //     console.log("hello world")
    // }();

    // 一種普遍的寫法 :
        
    // (function(){
    //     console.log("hello world1");
    // })()
    // 可能存在的bug;
    // (function(){
    //     console.log("hello world1");
    // })();  
    // //兩個匿名函數同時是使用一定要加上分號
    // (function(){
    //     console.log("hello world2");
    // })();
    // 建議寫法;
     ;(function(){
         console.log("hello world1");
     })();  

最後的最後,再來個總結吧!

1、全局不能訪問局部

2、局部可以拿到全局


喜歡的朋友可以點點關注,點點贊,歡迎評論區留言互動。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章