作用域鏈
之前看了《javascript高級程序設計》第三版,一直想想總結一下,但是由於拖延症而一推再推,今天終於開工啦,希望自己以後能夠更加勤快一點。當然都是我的個人理解,如有不對,歡迎指出。
首先總結一下作用域鏈的問題,說到JavaScript的作用域鏈,就要提一下那句老生常談的話
JavaScript是沒有塊級作用域的
那麼,javascript這門語言是如何面對變量命名以及使用的問題呢?
函數作用域
是的,JavaScript中是以函數爲一個單位,它不像c那樣是以‘{}’大括號爲邊界的。js中一個function即會生成一個作用域,最頂級的作用域也就是我們所說的全局變量所在的作用域,它在瀏覽器環境中就是window對象,在nodejs環境中是global對象,當我們在這層作用域用var或function聲明一個變量或函數,那麼這個變量或函數就會成爲頂級作用域的一個屬性。
var a=0;
console.log(window.a); //=>0(瀏覽器環境)
理解了頂級作用域,然後說一下函數作用域。之前說了js是以函數爲單位的,所以當我們在一個函數內聲明一個變量後,那麼這個變量只有在這個函數內部可以訪問,它的上層作用域是訪問不到的。
function foo(){
var tmp=1;
console.log(tmp);
}
foo(); //=>1
console.log(tmp); //Uncaught ReferenceError: tmp is not defined
那麼函數作用域內可以訪問上層作用域的變量嗎?
var tmp=1;
function foo(){
console.log(tmp);
}
foo(); //=>1 我們發現是可以訪問到的
那麼總結起來就是:js以函數爲一個單位,並伴隨函數的聲明生成一個作用域掛在上層作用域上,作爲它的屬性,而內部作用域可以訪問外部作用域的變量,但是外部作用域不能訪問內部的變量。理解了函數作用域後,那麼如果出現函數內的變量名與上層作用域內的變量名一樣的情況的話,會是什麼情況呢?
var global="global";
function foo(){
var global="local";
console.log(global);
}
foo(); //=>local
console.log(global) =>global
總結:我們發現,當變量名衝突時,js會以自身所在作用域內的變量爲準。可以理解爲,當js需要解析一個變量時,首先會在當前作用域內查找該變量,如果找到,則使用該變量,如果沒有找到,則向上層作用域內查找,然後按照這個邏輯往上查找,直到查找到頂級作用域的屬性上(也就是全局變量),若還未找到,則拋出異常。
說到這裏,下篇打算總結一下原型鏈的問題,同樣都是鏈,但這兩個鏈往上追朔的頂點是不一樣的,而且理解了原型鏈之後,那麼JavaScript中那些繼承的問題應該也就差不多理解了。
關於原型鏈的個人理解已發佈,如有興趣,請移步淺析JavaScript原型鏈
參考
- 《JavaScript權威指南》
- 《JavaScript高級程序設計》第三版