摘要:示例當一個函數創建后,它的作用域鏈會被創建此函數的作用域中可訪問的數據對象填充。每一個運行期上下文都和一個作用域鏈關聯。此時,作用域鏈中函數的所有局部變量所在的作用域對象會被推后,訪問代價變高了。
作用域
作用域就是變量與函數的可訪問范圍,即作用域控制著變量與函數的可見性和生命周期。
在JavaScript中,變量的作用域有全局作用域和局部作用域兩種。
函數對象有一個內部屬性[[Scope]],包含了函數被創建后的作用域中對象的集合,
這個集合被稱為函數的作用域鏈,它決定了哪些數據能被函數訪問。
示例:
當一個函數創建后,它的作用域鏈會被創建此函數的作用域中可訪問的數據對象填充。
function add(num1, num2){ var sum = num1 + num2; return sum; }
在函數add創建時,它的作用域鏈中會填入一個全局對象,該全局對象包含了所有全局變量,如下圖所示(注意:圖片只列舉了全部變量中的一部分):
執行add函數時會創建一個稱為“運行期上下文(execution context)”的內部對象,運行期上下文定義了函數執行時的環境。
每個運行期上下文都有自己的作用域鏈,用于標識符解析。
當運行期上下文被創建時,而它的作用域鏈初始化為當前運行函數的[[Scope]]所包含的對象,這些值按照它們出現在函數中的順序被復制到運行期上下文的作用域鏈中。
它們共同組成了一個新的對象,叫“活動對象(activation object)”,該對象包含了函數的所有局部變量、命名參數、參數集合以及this,然后此對象會被推入作用域鏈的前端,當運行期上下文被銷毀,活動對象也隨之銷毀。新的作用域鏈如下圖所示:
在函數執行過程中,每遇到一個變量,都會經歷一次標識符解析過程以決定從哪里獲取和存儲數據。該過程從作用域鏈頭部,也就是從活動對象開始搜索,查找同名的標識符,如果找到了就使用這個標識符對應的變量,如果沒找到繼續搜索作用域鏈中的下一個對象,如果搜索完所有對象都未找到,則認為該標識符未定義。函數執行過程中,每個標識符都要經歷這樣的搜索過程。
從作用域鏈的結構可以看出,在運行期上下文的作用域鏈中,標識符所在的位置越深,讀寫速度就會越慢。
如上圖所示,因為全局變量總是存在于運行期上下文作用域鏈的最末端,因此在標識符解析的時候,查找全局變量是最慢的。所以,在編寫代碼的時候應盡量少使用全局變量,盡可能使用局部變量。一個好的經驗法則是:如果一個跨作用域的對象被引用了一次以上,則先把它存儲到局部變量里再使用。
函數每次執行時對應的運行期上下文都是獨一無二的,所以多次調用同一個函數就會導致創建多個運行期上下文,當函數執行完畢,執行上下文會被銷毀。每一個運行期上下文都和一個作用域鏈關聯。一般情況下,在運行期上下文運行的過程中,其作用域鏈只會被 with 語句和 catch 語句影響。
with語句是對象的快捷應用方式,用來避免書寫重復代碼。
對with語句來說,會將指定的對象添加到作用域鏈中,對catch語句來說,會創建一個新的變量對象,其中包含的是被拋出的錯誤對象的聲明。
此時,作用域鏈中函數的所有局部變量所在的作用域對象會被推后,訪問代價變高了。
在實際應用中,應少用with,把catch中的錯誤委托給一個函數處理。
if(true){ var i = 0; i++; } console.log(i); //1
如果在c、c++或java語言中,if語句執行完畢后i會被銷毀,而在js中,if語句中的變量聲明是添加到了當前函數的執行環境中,所以在if語句之后仍然可以正常訪問。
模仿塊級作用域(function(){ //這里是塊級作用域 })();
將函數聲明包含在一對圓括號中,表示它實際上是一個函數表達式,而緊隨其后的另一對圓括號會立即調用這個函數。
小結作用域就是變量和函數的可訪問范圍,通常,局部環境中的變量和函數是不能被外部環境訪問的;
作用域鏈決定了哪些數據能夠被當前函數訪問以及訪問的順序;
函數創建時,會創建一個Global Object,填入它的作用域鏈;函數執行時,會創建一個運行期上下文的對象,它定義了函數執行時的環境。函數執行環境包含一個活動對象,該對象包含了函數的所有局部變量、命名參數、參數集合以及this,它會被推入作用域鏈的最前端;
函數執行過程,每遇到一個變量,都會經歷一次標識符解析的過程(逐級向上搜索作用域鏈)以決定從哪里獲取和存儲數據;
全局變量存在于運行期上下文作用域鏈的最末端,查找最慢,所以我們應該盡可能少使用全局變量,如果使用,就先用局部變量緩存下來;
在運行期上下文運行的過程中,其作用域鏈只會被 with 語句和 catch 語句影響,應少用with,把catch中的錯誤委托給一個函數處理;
js中沒有塊級作用域,但是我們可以模仿實現它。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/86111.html
前言 JavaScript中有一個被稱為作用域(Scope)的特性。雖然對于許多新手開發者來說,作用域的概念并不是很容易理解,本文我會盡我所能用最簡單的方式來解釋作用域和作用域鏈,希望大家有所收獲! 想閱讀更多優質文章請猛戳GitHub博客 作用域(Scope) 1.什么是作用域 作用域是在運行時代碼中的某些特定部分中變量,函數和對象的可訪問性。換句話說,作用域決定了代碼區塊中變量和其他資源的可見...
前言 JavaScript中有一個被稱為作用域(Scope)的特性。雖然對于許多新手開發者來說,作用域的概念并不是很容易理解,本文我會盡我所能用最簡單的方式來解釋作用域和作用域鏈,希望大家有所收獲! 想閱讀更多優質文章請猛戳GitHub博客 作用域(Scope) 1.什么是作用域 作用域是在運行時代碼中的某些特定部分中變量,函數和對象的可訪問性。換句話說,作用域決定了代碼區塊中變量和其他資源的可見...
摘要:作用域的類別可以影響到變量的取值,分為詞法作用域靜態作用域和動態作用域。而,采用的就是詞法作用域,或者叫靜態作用域。 關于javascript中的作用域和作用域鏈 我GitHub上的菜鳥倉庫地址: 點擊跳轉查看其他相關文章 文章在我的博客上的地址: 點擊跳轉 ? ? ? ? 前面的文章說到, 執行上下文的創建階段,主要有三個內容: ? ? ? ? 1、創建變量對象;2、初始化作用域...
摘要:注意由于閉包會額外的附帶函數的作用域內部匿名函數攜帶外部函數的作用域,因此,閉包會比其它函數多占用些內存空間,過度的使用可能會導致內存占用的增加。 作用域和作用域鏈是javascript中非常重要的特性,對于他們的理解直接關系到對于整個javascript體系的理解,而閉包又是對作用域的延伸,也是在實際開發中經常使用的一個特性,實際上,不僅僅是javascript,在很多語言中都...
摘要:作用域與作用域鏈每個函數都有自己的執行環境。這是初步了解作用域,如想更深入了解作用域,請看下面鏈接作用域原理作用域鏈由一道題圖解的作用域或者看權威指南和高級程序設計 本文是我學習JavaScript作用域整理的筆記,如有不對,請多指出。 作用域 一個變量的作用域是程序源代碼中定義這個變量的區域。 而在ES5中只分為全局作用域和函數作用域,也就是說for,if,while等語句是不會創建...
閱讀 1793·2021-11-18 10:02
閱讀 3524·2021-11-16 11:45
閱讀 1786·2021-09-10 10:51
閱讀 2105·2019-08-30 15:43
閱讀 1372·2019-08-30 11:23
閱讀 1484·2019-08-29 11:07
閱讀 1891·2019-08-23 17:05
閱讀 1394·2019-08-23 16:14