Javascript變量的作用域和作用域鏈詳解
工作這幾年,js學(xué)的不是很好,正好周末有些閑時間,索性買本《js權(quán)威指南》,大名鼎鼎的犀牛書,好好的把js深入的看一看。買過這本書的第一印象就是賊厚,不過后面有一半部分都是參考手冊。
一:作用域
說起變量第一個要說到的肯定就是作用域,正是因為不熟悉JS的作用域,往往就會把面向?qū)ο蟮淖饔糜驈埞诶畲?,畢竟有些東西總是習(xí)慣性的這樣,但是并不是每次照搬都是可以的,那么下一個問題就來了,js到底是什么作用域,當然是函數(shù)作用域了,我們的瀏覽器就是一個被實例化的window對象,如果在window下定義一個name字段,那么name字段就具有window這個函數(shù)作用域,也就是在window下都是可以訪問的,如果在window下定義一個function ctrip,然后里面再定義一個name,那么這個新定義的name只能在ctrip函數(shù)下通用,而老的name繼續(xù)在window下通用,舉個例子。
從圖中可以看出兩點:
1: 在window下定義了一個name,居然還可以在function下定義一個重名的name,這個在C#里面是不可想象的。
2:在JS下就可以做到眼瞎,它只認自己的作用域,所以就出現(xiàn)了第一個"second",你可能覺得這個沒有什么稀奇的地方,這是因為可能你還沒有真正理解什么是函數(shù)作用域,解析器在執(zhí)行ctrip的時候,第一件事情就是尋找ctrip下的所有局部變量,然后再執(zhí)行后續(xù)語句,既然是先尋找,那么var name="second"這條語句定義在ctrip中任何位置都是可以的,下面我們把語句調(diào)換過來。
可以看到在ctrip函數(shù)下,第一個console.log輸出的是undefined,這個結(jié)果可以證實,確實做了第一件事情是收集到了name這個局部變量,可能有人說為什么沒有變成”second“,那是因為初始化操作必須是逐語句執(zhí)行,所以在ctrip函數(shù)中執(zhí)行console.log(name)時,此時解析器只知道有一個未賦值的變量name,所以就console的時候就是undefined了。
二:作用域鏈
從上面的這個例子中我們也很清楚的知道了,在function中定義的變量只具有function范圍內(nèi)的作用域,同時我們也看到上面這個例子只是一層嵌套,window是個大的function,里面是一個ctrip的function,同樣的道理也可以延伸到多層嵌套,比如三層,四層。。。。N層,這些層就形成了一個鏈式結(jié)構(gòu)。
從圖中可以看到,我在ctrip下再定義了一個plane函數(shù),這樣的話就有三層了,輸出的結(jié)果也是我們希望看到的,每層的name只在自己的作用域范圍
內(nèi)生效,但是下面有一個問題來了,有一天我傻逼了,在定義plane的函數(shù)時,把 var name="third" 中的var忘記寫了,那么這個時候,plane中的
name到底是什么值呢? 是first還是second呢?
var name="first";
function ctrip(){
var name="second";
function plane(){
name="third";
console.log(name);
}
plane();
console.log(name);
}
ctrip();
console.log(name);
現(xiàn)在就是考驗?zāi)闶欠裾娴亩俗饔糜蜴?,仔細想想會發(fā)現(xiàn),當代碼執(zhí)行到plane函數(shù)中的name=”third“時,發(fā)現(xiàn)plane函數(shù)中并沒有name這個局部變量,恰好代碼又在ctrip這個大函數(shù)中,所以解析器就會回溯到ctrip函數(shù)中尋找name,發(fā)現(xiàn)果然有name,這個時候就把ctrip的name修改成了”third“。
又有一天,我喝多了酒又傻逼了一回,在定義plane函數(shù)的時候,把name="third" 錯寫成了 nam="third"; 丟了一個e,你可以說是酒精的問題,
又不是我代碼的問題。那么這個時候解析器該怎么處理呢?同樣的道理,在回溯時,發(fā)現(xiàn)ctrip沒有,再回溯到頂層的window下,發(fā)現(xiàn)還是沒有,
這個時候解析器做了這樣的處理,既然整個鏈中都沒有,你又賦值了,我總不能給你報錯,那多尷尬呀,就索性給你在window下隱式的定義一個
nam變量,這個時候nam其實就是全局變量了。我們可以在window頂層console一下nam看看。
好了,關(guān)于變量的東西也就這么多了,沒什么稀奇的,理解了就沒什么意思了。
相關(guān)文章
整理的比較全的event對像在ie與firefox瀏覽器中的區(qū)別
event對像在IE與FF中的區(qū)別,本文整理了很多,個人感覺還是比較全面的,需要的朋友可以收藏下2013-11-11typescript在node.js下使用別名(paths)無效的問題詳解
這篇文章主要給大家介紹了關(guān)于typescript在node.js下使用別名(paths)無效問題的相關(guān)資料,文中通過圖文以及示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2022-07-07JavaScript面向?qū)ο蟮某绦蛟O(shè)計(犯迷糊的小羊)
這篇文章主要介紹了JavaScript面向?qū)ο蟮某绦蛟O(shè)計(犯迷糊的小羊),需要的朋友可以參考下2018-05-05關(guān)于JavaScript中parseInt()的一個怪異行為解決
parseInt()是內(nèi)置的?JS?函數(shù),用于解析數(shù)字字符串中的整數(shù),下面這篇文章主要給大家介紹了關(guān)于JavaScript中parseInt()的一個怪異行為解決,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-12-12微信{"errcode":48001,"errmsg":"api unauthorized, hints: [ req_
這篇文章主要介紹了微信{"errcode":48001,"errmsg":"api unauthorized, hints: [ req_id: 1QoCla0699ns81 ]"},非常具有實用價值,需要的朋友可以參考下2018-10-10