JavaScript 進階(二)變數範圍

來源:互聯網
上載者:User

標籤:調用   alert   賦值   返回   閉包   c語言   題目   例子   span   

局部變數陷阱

先看一段代碼:

  1. function foo() {  
  2.     var a = "hello"  
  3.     b = "world"  
  4.     return a + b;  
  5. }  

這個函數執行完成之後返回helloworld,結果確實沒有問題。但是裡面有一個細節就是兩個局部變數一個前邊有var,另一個沒有。這似乎並不影響執行,但是事實上沒有var的話,這個變數就變成了全域變數。你在這個函數外面調用一下alert(b)試一下就知道了。一個莫名其妙冒出來的全域變數在有時候會引起匪夷所思的bug,所以一定要記得局部變數聲明前一定要用var

變數聲明提升

再看一段代碼:

  1. var foo = "hello"  
  2. function test() {  
  3.     alert(foo);  
  4.     var foo = "world";  
  5. }  
  6. test()  

代碼執行時,請問alert的內容是什麼呢?答案是undefined。從直覺上來講,運行alert的時候,foo這個變數沒有聲明,不存在。既然局部範圍沒有,那就去全域範圍找,應該是"hello"才是啊。為什麼呢?這就是變數聲明提升。函數內的任何變數的聲明都會被提升至函數的頂部,所以上面的test函數相當於

  1. function test() {  
  2.     var foo;  
  3.     alert(foo);  
  4.     foo = "world";  
  5. }  

所以會是undefined。這裡注意提升的只是聲明,賦值的代碼還在原來的地方。並且聲明的部分與聲明的代碼是否執行無關,比如

  1. function test() {  
  2.     alert(foo);  
  3.     if(false) {  
  4.         foo = "world";  
  5.     }  
  6. }  

把test函數修改成這個樣子,執行結果仍然是一樣。聲明仍然被提前了,儘管這行代碼將不會被運行。
這就是變數聲明提升,我們再看一個例子

  1. function test() {  
  2.     foo1();  
  3.     foo2();  
  4.     function foo1(){alert("foo1")}  
  5.     var foo2 = function(){alert("foo2")}  
  6. }  

當test函數執行的時候,結果如何呢?結果是foo1被alert出來,然後JS報錯"undefined is not a function"。這裡在函數內部聲明函數的提升有點區別。foo1,用函數的方式聲明定義一個函數,則聲明與函數體都被提升了,但是foo2用變數的方式定義函數,被提升的只有聲明,函數體沒有被提升,所以執行foo2()的時候,foo2沒有被賦值,是undefined。

看起來由於JS裡面有變數聲明提升,那麼就無法使用C語言裡面的塊級範圍,那麼我確實想用,怎麼辦呢?有一個辦法是用匿名函數,舉例如下:

  1. var foo = "hello"  
  2. function test() {  
  3.     alert(foo);  
  4.     (function(){  
  5.         var foo = "world";  
  6.     })()  
  7. }  
  8. test()  

當test函數改成這個樣子的時候,alert出來的結果就是"hello"了,匿名函數裡面的foo就無法作用到其他地方。

閉包中的局部變數

我之前招聘前端,問了應聘者這樣一個題目,說請寫一個可以返回遞增整數序列的函數,他給我的答案是這樣

  1. var i = 0;  
  2. function increase() {return i++;}  

當反覆調用函數increase的時候,就會返回遞增序列。但是我接著問,如果有人失手改了i怎麼樣,他語塞。其實這個問題的關鍵是說要製造一個很安全的地方來放置這個i,讓這個變數只能被一個函數訪問,所以一個可選的答案是這樣。此時increase就是會返回遞增序列。並且i放在了一個很安全的地方。就不會被破壞了。

  1. var increase = (function() {  
  2.     var i = 0;  
  3.     return function(){return i++;}  
  4. })();  

JS的閉包是一個很值得講的內容,好用,但是也有不少坑,下面我專門開一篇文章來講。

全域變數

無數講高品質代碼的書籍都會提到全域變數這個大殺器,程式員們都被反覆告誡,除非你又充足的理由,否則不要使用全域變數,JS也不例外。然而JS有一個特殊的地方就是沒有main方法,入口的代碼一定要寫,但是寫在這地方的代碼難免要用到變數,這些變數就是全域變數了,那麼如何處理這個問題呢?答案還是匿名函數,像這樣:

  1. (function(){  
  2.     var a = "a";  
  3.     var b = "b";  
  4.     var c = "c";  
  5.     foo(a, b, c);  
  6. })()  

把入口代碼放到一個匿名函數中,這樣這些變數a, b, c就會被藏到這個函數裡面,就避免了全域變數的出現。

JavaScript 進階(二)變數範圍

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.