每個JavaScript函數都是一個對象,對象中有屬性,可以訪問如:
function text(){}
console.log(text.name) // text
還有一些屬性是我們訪問不了的如:
function text(){}
console.log(text.[[scope]]) //報錯
[[scope]]是函數的屬性,但是是一種隱式的屬性,我們訪問不了,而他代表的就是函數產生的作用域,存儲了執行期上下文的集合。它既然用不了,那它還有作用嗎?有的雖然我們用不了,但是系統是可以使用的(只許州官放火不許百姓點燈)。
執行期上下文:當函數執行前,會創建一個執行期上下文的對象,執行期上下文定義了一個函數執行時的環境(我也不知道該怎麼解釋這句,就是這個函數會依賴這個環境去執行,,,大家試着去理解就可以),函數每次執行時對應的執行期上下文都是獨一無二的,所以多次調用一個函數會產生多個執行期上下文,但是這麼多執行期上下文放着也沒用,還佔內存,所以函數執行完畢以後就會銷燬它自己產生的執行期上下文。
function text(){} //函數創建產生AO{}
text(); // 函數執行 銷燬AO對象,盡顯渣男本色
作用域鏈: [[scope]]中所存的執行期上下文對象的集合,這個集合成鏈式鏈接,我們把這中鏈式鏈接叫做作用域鏈。
好了看天書環節過去了,可以看代碼說問題了:
var c = 10;
function a(){ // 在a函數剛剛被定義的時候,它就有了自己的[[scope]]屬性 裏面第一位放着全局對象GO
console.log(c) // 10 ,在AO裏找不到c變量,就到GO裏找到c 打印10
function b(){ //在b函數剛剛被定義的時候,它就有了自己的[[scope]]屬性 裏面第一位放着a函數創建時的AO,第二位放着全局對象GO
var b = 234;
}
var a = 123;
b();//函數執行時在[[scope]]屬性裏面把自己創建的AO放在作用域鏈的頂端,AO和GO向下移一位。
}
var glob = 100;
a(); //函數執行時在[[scope]]屬性裏面把自己創建的AO放在作用域鏈的頂端,GO向下移一位。
a,b函數定義和執行時他們能訪問到的作用域及訪問先後順序
a 定義 a.[[scope]] ---------------- 0 : GO
a 執行 a.[[scope]] ---------------- 0 : aAO
1 : GO
b 定義 b.[[scope]] ---------------- 0 : aAO
1 : Go
b 執行 b.[[scope]] ---------------- 0 : bAO
1 : aAO
2 : GO
函數在執行時,會產生AO,當它訪問變量時,先去找AO,再去找GO,這其實說明這樣他們之間有一種聯繫,即作用域鏈。而自己創建的AO永遠放在作用域鏈的頂端。
最後當b函數執行完畢,b函數銷燬自己的AO對象,保留a函數的AO和全局的GO,處於定義階段,等待執行,截止a函數也執行完畢時,a函數銷燬自己的AO對象,保留全局GO對象,等待執行,但是注意一點,a函數的AO對象中,是有b函數的定義的,a函數的AO也保留在b函數的定義中,所以a函數的AO沒有被真正意義上的銷燬。
還有一點:a函數執行創建一個自己的AO,內部的b函數也可以訪問這個AO,哪兩個AO有什麼關係呢?是複製了一個,還是大家用的同一個呢?看代碼:
function a() {
var cc = 0;
function b() {
cc = 10;
}
b();
console.log(cc) // 10 打印出了10,這說明b函數訪問的AO對象和a函數創建的AO對象是同一個。
}
a();
入職不久的小前端從今以後開始自己的技術分享之旅,歡迎建議和批評。