有過相似C語言編程經驗的同窗應該都知道「塊級做用域(block scope)」:花括號內的每一段代碼都具備各自的做用域,並且在聲明它們的代碼段以外是不可見的。而在JavaScript中是沒有塊級做用域的,JavaScript取而代之地使用了「函數做用域(function scope)」:變量在聲明它們的函數體以及這個函數體嵌套的任意函數體內都是有定義的。編程
光用文字解釋平白無味,先來段讓你爲之一振的代碼:瀏覽器
function myTest(num){ var i = 0; if(num == 222){ var j = 0; for(var k=0; k<2; k++){ console.log(k); } console.log(k); } console.log(i); console.log(j); console.log(k); console.log(m); } myTest(111);
請認真閱讀代碼,仔細思考,認真回答問題。下面給出瀏覽器中運行的結果,檢驗下本身的答案吧!函數
若是你徹底回答正確,而且已經明白全部緣由,那麼就不必看下去了;若是你還未明白緣由而且有一顆好奇、意欲一探究竟的心,那麼就下來就要認真看完本博客了。學習
既然不懂,那就再繼續認真看解釋唄:JavaScript的函數做用域是指在函數內聲明的全部變量在函數體內始終是可見的,這就意味着變量在聲明以前甚至已經可用了。JavaScript這個特性被非正式地稱爲聲明提早,即JavaScript函數裏聲明的全部變量(但不涉及賦值)都被提早至函數體的頂部了。這麼說上面的例子中代碼就等同於spa
function myTest(num){ var i,j,k; i = 0; if(num === 222){ j = 0; for(k=0; k<2; k++){ console.log(k); } console.log(k); } console.log(i); console.log(j); console.log(k); console.log(m); }
因此即便代碼運行時沒有進入if條件語句中,但變量i,j,k已經聲明瞭(即便是在for循環中聲明的k聲明也提早了呢),只是i初始化爲0,而j,k沒有初始化而已,因此j,k輸出是undefined。至於m,由於它根本就沒有聲明過,因此調用時就報錯了。如今明白了吧,下面再來一題本身檢測下掌握狀況吧:code
var str1= "out1"; var str2 = "out2"; function myTest(){ console.log(str1); console.log(str2); var str2 = "inner"; console.log(str2); }
myTest();
結果是什麼呢?下面給出瀏覽器的回答,檢驗一下你心中的答案吧!blog
給JS學習者一個建議:儘可能將變量聲明放在函數體頂部,而不是將聲明放在使用變量之處,這種作法會使代碼清晰地反映了真實的變量的做用域。ip
補充內容:通過最近的學習,發現這篇博客寫的時候本身學的仍是不夠全面,下面增長一段補充內容:作用域
①var 和 function 都是聲明語句,它們聲明或定義變量或函數。博客
②變量在聲明它們的腳本或函數中都是有定義的,變量聲明語句會被「提早」至腳本或者函數的頂部,可是初始化操做還在原來賦值語句的位置執行,未初始化的變量的值是undefined。
③函數聲明語句(注意不是函數定義表達式)中的函數會被顯示地「提早」到了腳本或函數的頂部,所以它們在整個腳本和函數內都是可見的,這個時候函數名稱和函數體均會提早,也就是說能夠在聲明一個JavaScript函數以前調用它。關於函數定義表達式,即便用var來定義一個函數,這種形式只有變量聲明提早了,變量的初始化仍在原來位置,這時候就不能在初始化以前調用這個函數了。若是不懂這兩種函數定義的形式,請繼續閱讀:下面立刻就有例子來區別說明了。
這裏要重點補充的就是:JavaScript中不止在函數中有變量聲明提早,在函數外也有變量聲明提早。下面仍是用代碼說話:
正如預料之中,console.log(aa)輸出結果是undefined,而console.log(bb)卻由於變量bb在任何位置都沒有聲明因此就報錯。
再來講說函數聲明語句中函數提早的問題,先看一個函數聲明語句的例子:
看到了吧,myConsoleLog 函數就是經過函數聲明語句定義的,因此它的函數名和函數體都會提早至頂部,因此在聲明語句以前就能夠調用它了,下面繼續說一個函數定義表達式的例子:
此次的 myConsoleLog 函數就是經過函數定義表達式定義的,因此myConsoleLog 就是使用var 聲明的其餘普通變量同樣,只有聲明提早了,但它初始化仍是在第三行那裏,因此第一行輸出變量myConsoleLog的值就是undefined嘍,第二行調用更是會報錯了,由於如今myConsoleLog還只是一個值爲undefined的普通變量呢,怎麼能夠做爲一個函數來調用啊。
補充就先到這裏吧!!!
下面是在下衷心送給各位看官的五個歡迎(O(∩_∩)O~):歡迎轉載、歡迎收藏、歡迎評論、歡迎點贊、歡迎推薦!