深刻理解JavaScript的函數做用域

什麼是做用域 ?

做用域:一個變量能夠生效的範圍。 變量不是在全部地方均可以使用的,而這個變量的使用範圍就是咱們要說的做用域。瀏覽器

注意:在JavaScript中,劃分做用域也是用大括號劃分的, 可是在 JS 之中可以有效限定做用域的大括號只有函數大括號!函數

有哪些做用域 ?

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

學習使用做用域,如下內容是所須要瞭解的:學習

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

請看下面示例代碼:spa

1     var a = 10;
2     console.log(a);  // 輸出結果: 10
3     function foo(){
4         console.log(a);  // 輸出結果: 10
5     }
6     foo()

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

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

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

一樣的,如下內容也是所須要瞭解的:blog

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

請看下面示例代碼:生命週期

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

經過上面示例代碼能夠看出:ip

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

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

咱們見慣了常規狀況,如今看一個特殊狀況:

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

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

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

請看下面示例代碼:

1   function foo(){
2         a = 10; // 此時聲明變量 a 沒有使用var關鍵字聲明
3         console.log(a); // 10
4     }
5     foo();
6     console.log(a); // 輸出 10,不報錯了;

看完上面的代碼示例,你是否是以爲這不挺好的嘛,變量 a 能夠隨便使用,都不用報錯了,爲何不讓使用??

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

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

你會發現:

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

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

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

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

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

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

就是你啥時候能夠訪問!

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

致使的結果就是會讓程序變得更重! 若是可能,仍是少設計一點全局變量吧!對你們都好

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

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

咱們看完了生命週期,再來一塊兒看一下命名空間吧!

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

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

咱們先來舉一個小例子,話很少說上代碼:

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

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

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

能夠用匿名函數來解決命名空間的問題

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

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

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

 1     // 讓匿名函數經歷一次運算:  若是函數發生了特定的運算,那麼這個函數就會被當作一個地址;
 2     // var res = 1 + function(){} 
 3     // console.log(res); //運行結果:1function(){}
 4     
 5     // 利用這個機制使用匿名函數當即調用 : 
 6     // +function(){
 7     //     console.log("hello world")
 8     // }();
 9     
10     // 函數通過運算變成了地址,被後面的調用運算符調用了;
11     // !function(){
12     //     console.log("hello world")
13     // }();
14 
15     // 一種廣泛的寫法 :
16         
17     // (function(){
18     //     console.log("hello world1");
19     // })()
20     // 可能存在的bug;
21     // (function(){
22     //     console.log("hello world1");
23     // })();  
24     // //兩個匿名函數同時是使用必定要加上分號
25     // (function(){
26     //     console.log("hello world2");
27     // })();
28     // 建議寫法;
29      ;(function(){
30          console.log("hello world1");
31      })();  

 

最後來個總結吧!

一、全局不能訪問局部

二、局部能夠拿到全局

 


 

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

相關文章
相關標籤/搜索