大家好,我是IT修真院武漢分院第10期學員余佳貝,一枚正直善良的web程序員。
今天給大家分享一下,修真院官網(wǎng)js任務4,深度思考中的知識點——如何理解js中的作用域與作用域鏈
一.背景介紹
什么是作用域呢,簡單的說,作用域就是變量與函數(shù)的可訪問范圍,即作用域控制著變量與函數(shù)的可見性和生命周期。在JavaScript中,變量的作用域有全局作用域和局部作用域兩種。
二.知識剖析
1.全局作用域(Global Scope)
在代碼中任何地方都能訪問到的對象擁有全局作用域,一般來說一下幾種情形擁有全局作用域:
(1)在函數(shù)外面定義的變量擁有全局作用域,例如:
varauthorName ="山邊小溪";functiondoSomething(){
alert(authorName);
}
doSomething();
(2)所有末定義直接賦值的變量自動聲明為擁有全局作用域,例如:
functiondoSomething(){varauthorName="山邊小溪";
blogName="夢想天空";
alert(authorName);
}
doSomething();//山邊小溪
alert(blogName);//夢想天空
alert(authorName);//腳本錯誤
變量blogName擁有全局作用域,而authorName在函數(shù)外部無法訪問到。
(3)所有window對象的屬性擁有全局作用域
一般情況下,window對象的內(nèi)置屬性都都擁有全局作用域,例如window.name、window.top等等。
varsite ='baidu.com';functiongetSite(){
alert(this.site);
}
alert(window.site);// 'baidu.com'
getSite();// 'baidu.com'
window.getSite();// 'baidu.com'
在上面示例中,site變量和getSite()方法沒有指定上級對象,所在二者會被添加到window全局對象,所以直接訪問二者與通過window訪問本質(zhì)相同(如,直接訪問getSite()與使用window.getSite()訪問一樣)。
1. 局部作用域(Local Scope)
和全局作用域相反,局部作用域一般只在固定的代碼片段內(nèi)可訪問到,最常見的例如函數(shù)內(nèi)部,所有在一些地方也會看到有人把這種作用域成為函數(shù)作用域
例如下列代碼中的bName和函數(shù)innerSay都只擁有局部作用域:
functiondoSomething(){varbName="雙擊66";functioninnerSay(){
alert(bName);
}
innerSay();
}
alert(bName);//腳本錯誤
innerSay();//腳本錯誤
作用域鏈(Scope Chain)
說完了作用域我們就可以接著來聊聊作用域鏈(Scope Chain)這個概念了.作用域鏈就是由多個作用域組成的 在JS中,函數(shù)的可以允許嵌套的。即,在一個函數(shù)的內(nèi)部聲明另一個函數(shù).類似這樣:
functionA(){
????vara=1;
????functionB(){//在A函數(shù)內(nèi)部,聲明了函數(shù)B,這就是所謂的函數(shù)嵌套。
????????varb=2;
????}
}
對于A來說,A函數(shù)在執(zhí)行的時候,會創(chuàng)建其A函數(shù)的作用域, 那么函數(shù)B在創(chuàng)建的時候,會引用A的作用域,類似下面這樣

函數(shù)B在執(zhí)行的時候,其作用域類似于下面這樣:

從上面的兩幅圖中可以看出,函數(shù)B在執(zhí)行的時候,是會引用函數(shù)A的作用域的。所以,像這種函數(shù)作用域的嵌套就組成了所謂的函數(shù)作用域鏈。當在自身作用域內(nèi)找不到該變量的時候,會沿著作用域鏈逐步向上查找,若在全局作用域內(nèi)部仍找不到該變量,則會拋出異常。
三.常見問題
如何更加直觀的體現(xiàn)作用域鏈
四.解決方案
五.編碼實戰(zhàn)
六.拓展思考
如何運用作用域鏈的知識進行性能優(yōu)化
其實作用域鏈就是JS引擎查詢數(shù)據(jù)的一個鏈表,后定義的覆蓋先定義的,查詢不到定義的數(shù)據(jù)就往深一層查詢,一直到全局作用域為止 但是越往內(nèi)層延伸,讀寫速度就會越慢,查找全局變量是最慢的。所以,在編寫代碼的時候應盡量少使用全局變量,盡可能使用局部變量。 如果一個跨作用域的對象被引用了一次以上,則先把它存儲到局部變量里再使用。例如下面的代碼:
functionchangeColor(){document.getElementById("btnChange").onclick=function(){document.getElementById("targetCanvas").style.backgroundColor="red";
};
}
這個函數(shù)引用了兩次全局變量document,查找該變量必須遍歷整個作用域鏈,直到最后在全局對象中才能找到。這段代碼可以重寫如下:
functionchangeColor(){vardoc=document;
doc.getElementById("btnChange").onclick=function(){
doc.getElementById("targetCanvas").style.backgroundColor="red";
};
}
這段代碼比較簡單,但是如果程序中有大量的全局變量被從反復訪問,那么重寫后的代碼性能會有顯著改善。
七.參考文獻
八.更多討論