JavaScript基礎(11.JS難點:作用域詳解)
先來個其他語言的例子:
不用仔細考慮它是什麼意思,注意一點即可:
在內層大括號裡面定義了一個string型的name變數,卻在大括號外面用它,因此會報錯。
我們繼續:
在Python中:
情況一可以執行,而情況二會出錯。
到底是為什麼呢?
這裡用簡單的一句話來解釋就可以:
在其他語言中是作用域以塊({})為單位的,在Python裡面作用域是以函式作為單位的。、
因此,函式內部定義的變數可以在函式內部任意使用,但是在函式外部就不能用了。
如這裡的func()可以成功執行,但是print(name)就會出錯。
接下來我們來看JS:
1.它預設是以函式為作用域的!所以它和Python是一樣的。
成功!
對了,在console裡面要換行的話,按shift+回車,否則就直接執行了,當時寫這裡的時候還不知道。
2.函式的作用域在沒有執行之前(即在沒有被呼叫之前)就已經建立!
3.函式的作用域存在作用域鏈,並且也是在被呼叫之前建立!
一個函式套一個函式產生作用域鏈。
現在這個函式執行後輸出tony,解釋見下
當console.log(xo)執行時候,首先找當前函式下的xo變數,找到tony,如果註釋掉tony,它就會找外一層函式裡面的xo變數,找到eric,如果再註釋掉它,就會找外部變數xo,找到alex。如果alex不存在,就會報錯!
我們繼續深入:
這裡的func函式的返回值為inner函式,因此ret()就相當於是呼叫inner函式
然而並不會輸出alex,輸出的是eric
先執行ret = func()
作用域鏈裡面的xo就是eric,然後返回了inner。
開始執行ret() ,先找最內側沒有xo,然後找外層xo就是eric
繼續深入:
這時候會輸出的是tony;
因為前一步的ret = func() 執行後,func作用域鏈裡面的xo變數由eric變成tony,
ret()執行的時候,現在最內層找,找不到,然後外層找,外層的xo變成了tony,所以輸出tony
4.JavaScript特有的:內部區域性變數會提前宣告:
當直譯器解釋函式的時候,生成作用域鏈,在生成的同時,還會有另外一個操作:
宣告所有的變數,但是並沒有定義。
這句話的意思就是,函式裡邊如果第一行要使用某個變數,但是在第n行定義了它。這在C++裡面會報錯的,但是在JS裡面會會輸出一個undefined。