摘要:作用域與作用域鏈每個函數都有自己的執行環境。這是初步了解作用域,如想更深入了解作用域,請看下面鏈接作用域原理作用域鏈由一道題圖解的作用域或者看權威指南和高級程序設計
本文是我學習JavaScript作用域整理的筆記,如有不對,請多指出。
作用域一個變量的作用域是程序源代碼中定義這個變量的區域。
而在ES5中只分為全局作用域和函數作用域,也就是說for,if,while等語句是不會創建作用域的。ES6(let,const)除外。
//全局作用域 var a = 123; function aa () { //局部作用域 var b = 456; }聲明提前
JavaScript函數里聲明的所有變量(但不涉及賦值)都被“提升”至函數體的頂部,在代碼開始運行之前。這個特性被稱為聲明提前。
var a = "g"; function f() { console.log(a); //輸出undefined var a = "l"; console.log(a); //輸出"l" }
由于函數作用域的特性,局部變量在整個函數體始終是有定義的,也就是說,函數體的局部變量覆蓋了同名全局變量。在函數體內,變量a被“提前”了,提前至函數體的頂部,所以第一次輸出的是undefined,那時候還沒賦值,但代碼執行到var語句時候,局部變量才會被賦值。因此第二次輸出則是“l”。此代碼過程如下:
var a = "g"; function f() { var a; console.log(a); //輸出undefined a = "l"; console.log(a); //輸出"l" }
因此一些程序員特意將變量聲明放在函數體的頂部,而不是將聲明靠近放在使用變量之處。
作用域鏈先看一段簡單代碼,代碼如下:
var name = "wythe"; function one () { console.log(name); //wythe var firend = "zero"; } one(); console.log(firend); //報錯
看到代碼可知,name是在全局作用域中聲明的全局變量,而firend則是在函數作用域中聲明的局部變量。在執行時候你會發現函數作用域能夠訪問到在全局作用域中name這個變量,而全局作用域卻不能訪問到函數作用域的friend的變量,原因是作用域鏈!
作用域鏈的規則:
外部不能訪問內部變量,內部可以訪問外部變量
為什么會有這樣規則?因為是執行環境所規定的。
執行環境定義了變量或函數有權訪問其他數據,決定了它們的行為。每個執行環境都有一個與之關聯的變量對象(variable object),環境中定義的所有變量和函數都保存在這個對象中。
全局執行環境是最外圍的一個執行環境。在Web瀏覽器中,全局執行環境被認為是window對象。某個執行環境中所有所有代碼執行完畢后,該環境被銷毀,保存在其中的所有的變量和函數定義也隨之銷毀。
補充說明:需要了解一些概念,變量對象(Variable Object)、活動對象(Activation Object)、函數的屬性[[scope]].
變量對象指的是變量對象(縮寫為VO)是一個與執行上下文相關的特殊對象,它存儲著在上下文中聲明的內容有:變量 (var, 變量聲明)、函數聲明和函數的形參。
執行上下文(執行環境):每次當控制器轉到ECMAScript可執行代碼的時候,即會進入到一個執行上下文。執行上下文(簡稱-EC)是ECMA-262標準里的一個抽象概念,用于同可執行代碼(executable code)概念進行區分。
活動對象指的是由函數的運行期上下文(代碼執行前)創建,在運行時可變,初始時只有 arguments 屬性,通過變量的初始化,包含了局部變量、命名參數、 this 等
湯姆大叔深入理解JavaScript變量對象
函數屬性[[scope]]指的是函數對象都有一個內部屬性 [[scope]],函數被創建后,函數 [[scope]] 屬性會被創建此函數的作用域中可訪問的數據對象填充,是所有父變量對象的層級鏈。[[scope]] 在函數被創建時靜態存儲,永遠不會改變,直至銷毀。
作用域與作用域鏈
每個函數都有自己的執行環境。當執行流進入一個函數時,函數的環境就會被推入一個環境棧中。而在函數執行之后,棧將環境彈出,把控制權返回之前的執行環境。當代碼在一個環境執行時候,會創建變量對象的一個作用域鏈(scope chain)。作用域的前端,始終都是當前執行的代碼所在環境的變量對象。如何這個環境是函數,則將其活動對象(activation object)作為變量對象?;顒訉ο笤谧铋_始只包含一個變量,即arguments對象(這個對象在全局環境是不存在)。作用域鏈中的下一個變量對象來自包含(外部)環境,而再下一個變量對象則來自下一個包含對象。這樣,一直延續到全局執行環境;全局執行環境的變量對象始終都是作用域中的最后一個對象。
根據這個概念圖解上面代碼:
在函數one創建時,它的作用域鏈中會填入一個全局對象,該全局對象包含了所有全局變量,當執行流執行到one()語句時,會創建函數one執行環境。將函數one執行環境。如果這個環境是函數,則創建一個活動對象,然后此對象會被推入作用域鏈的前端,當函數執行完畢后,活動對象也隨之銷毀。新的作用域鏈如下圖所示:
標識符解析是沿著作用域一級一級地搜素標識符的過程。搜素過程始終從作用域的前端開始,然后逐級地向后回溯,直到找到標識符為止,找不到,會導致錯誤發生。內部環境可以通過作用域鏈訪問所有外部環境,但外部環境不能訪問內部環境中任何變量和函數。這些環境之間的聯系是線性,有次序的。
這是初步了解作用域,如想更深入了解作用域,請看下面鏈接:
JavaScript作用域原理
JavaScript作用域鏈
由一道題圖解JavaScript的作用域
或者看《JavaScript權威指南》和《JavaScript高級程序設計》
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/86548.html
摘要:開篇作用域是每種計算機語言最重要的基礎之一,因此要想深入的學習作用域和作用域鏈就是個繞不開的話題。這樣由多個執行上下文的變量對象構成的鏈表就叫做作用域鏈。這時候執行上下文的作用域鏈,我們命名為至此,作用域鏈創建完畢。 開篇 作用域是每種計算機語言最重要的基礎之一,因此要想深入的學習JavaScript,作用域和作用域鏈就是個繞不開的話題。 在《深入學習js之—-執行上下文棧》中我們提到...
摘要:在代碼執行時,對應的作用域鏈常常是保持靜態的。當語句執行完畢后,會把作用域鏈恢復到原始狀態。在全局作用域中創建的函數,其作用域鏈會自動成為全局作用域中的一員。 列表項目 前言 學習了javascript已經很久了,關于這個語言中的這兩個特性也是早已耳熟能詳,但是在實際的使用的過程中或者是遇到相關的問題的時候,還是不能很好的解決。因此我覺得很有必要深入的學習并且記錄這個問題,以便在今后的...
摘要:在中的應用采用詞法作用域,也就是靜態作用域。那什么又是詞法作用域或者靜態作用域呢請繼續往下看靜態作用域與動態作用域因為采用的是詞法作用域函數的作用域在函數定義的時候就決定了。 開篇 當我們在開始學習任何一門語言的時候,都會接觸到變量的概念,變量的出現其實是為了解決一個問題,為的是存儲某些值,進而,存儲某些值的目的是為了在之后對這個值進行訪問或者修改,正是這種存儲和訪問變量的能力將狀態給...
摘要:具體來說就是當執行流進入下列任何一個語句時,作用域鏈就會得到加長語句的塊和語句。這兩個語句都會在作用域鏈的前端添加一個變量對象。對來說,會將指定的對象添加到作用域鏈中。 1. 基本類型和引用類型的值 JavaScript變量可以用來保存兩種類型的值:基本類性值和引用類性值?;绢愋椭翟醋砸韵?種基本數據類型:Undefined、Null、Boolean、Number和String?;?..
摘要:示例當一個函數創建后,它的作用域鏈會被創建此函數的作用域中可訪問的數據對象填充。每一個運行期上下文都和一個作用域鏈關聯。此時,作用域鏈中函數的所有局部變量所在的作用域對象會被推后,訪問代價變高了。 作用域 作用域就是變量與函數的可訪問范圍,即作用域控制著變量與函數的可見性和生命周期。在JavaScript中,變量的作用域有全局作用域和局部作用域兩種。 作用域鏈 函數對象有一個內部屬性[...
閱讀 1382·2021-09-22 10:02
閱讀 1862·2021-09-08 09:35
閱讀 4044·2021-08-12 13:29
閱讀 2594·2019-08-30 15:55
閱讀 2257·2019-08-30 15:53
閱讀 2295·2019-08-29 17:13
閱讀 2753·2019-08-29 16:31
閱讀 2948·2019-08-29 12:24