標籤:調用 alert 賦值 返回 閉包 c語言 題目 例子 span
局部變數陷阱
先看一段代碼:
- function foo() {
- var a = "hello"
- b = "world"
- return a + b;
- }
這個函數執行完成之後返回helloworld,結果確實沒有問題。但是裡面有一個細節就是兩個局部變數一個前邊有var,另一個沒有。這似乎並不影響執行,但是事實上沒有var的話,這個變數就變成了全域變數。你在這個函數外面調用一下alert(b)試一下就知道了。一個莫名其妙冒出來的全域變數在有時候會引起匪夷所思的bug,所以一定要記得局部變數聲明前一定要用var
變數聲明提升
再看一段代碼:
- var foo = "hello"
- function test() {
- alert(foo);
- var foo = "world";
- }
- test()
代碼執行時,請問alert的內容是什麼呢?答案是undefined。從直覺上來講,運行alert的時候,foo這個變數沒有聲明,不存在。既然局部範圍沒有,那就去全域範圍找,應該是"hello"才是啊。為什麼呢?這就是變數聲明提升。函數內的任何變數的聲明都會被提升至函數的頂部,所以上面的test函數相當於
- function test() {
- var foo;
- alert(foo);
- foo = "world";
- }
所以會是undefined。這裡注意提升的只是聲明,賦值的代碼還在原來的地方。並且聲明的部分與聲明的代碼是否執行無關,比如
- function test() {
- alert(foo);
- if(false) {
- foo = "world";
- }
- }
把test函數修改成這個樣子,執行結果仍然是一樣。聲明仍然被提前了,儘管這行代碼將不會被運行。
這就是變數聲明提升,我們再看一個例子
- function test() {
- foo1();
- foo2();
- function foo1(){alert("foo1")}
- var foo2 = function(){alert("foo2")}
- }
當test函數執行的時候,結果如何呢?結果是foo1被alert出來,然後JS報錯"undefined is not a function"。這裡在函數內部聲明函數的提升有點區別。foo1,用函數的方式聲明定義一個函數,則聲明與函數體都被提升了,但是foo2用變數的方式定義函數,被提升的只有聲明,函數體沒有被提升,所以執行foo2()的時候,foo2沒有被賦值,是undefined。
看起來由於JS裡面有變數聲明提升,那麼就無法使用C語言裡面的塊級範圍,那麼我確實想用,怎麼辦呢?有一個辦法是用匿名函數,舉例如下:
- var foo = "hello"
- function test() {
- alert(foo);
- (function(){
- var foo = "world";
- })()
- }
- test()
當test函數改成這個樣子的時候,alert出來的結果就是"hello"了,匿名函數裡面的foo就無法作用到其他地方。
閉包中的局部變數
我之前招聘前端,問了應聘者這樣一個題目,說請寫一個可以返回遞增整數序列的函數,他給我的答案是這樣
- var i = 0;
- function increase() {return i++;}
當反覆調用函數increase的時候,就會返回遞增序列。但是我接著問,如果有人失手改了i怎麼樣,他語塞。其實這個問題的關鍵是說要製造一個很安全的地方來放置這個i,讓這個變數只能被一個函數訪問,所以一個可選的答案是這樣。此時increase就是會返回遞增序列。並且i放在了一個很安全的地方。就不會被破壞了。
- var increase = (function() {
- var i = 0;
- return function(){return i++;}
- })();
JS的閉包是一個很值得講的內容,好用,但是也有不少坑,下面我專門開一篇文章來講。
全域變數
無數講高品質代碼的書籍都會提到全域變數這個大殺器,程式員們都被反覆告誡,除非你又充足的理由,否則不要使用全域變數,JS也不例外。然而JS有一個特殊的地方就是沒有main方法,入口的代碼一定要寫,但是寫在這地方的代碼難免要用到變數,這些變數就是全域變數了,那麼如何處理這個問題呢?答案還是匿名函數,像這樣:
- (function(){
- var a = "a";
- var b = "b";
- var c = "c";
- foo(a, b, c);
- })()
把入口代碼放到一個匿名函數中,這樣這些變數a, b, c就會被藏到這個函數裡面,就避免了全域變數的出現。
JavaScript 進階(二)變數範圍