摘要:當代碼在一個環境中執行時,會創建變量對象的一個作用域鏈,作用域鏈的用途,是保證對執行環境有權訪問的所有變量和函數的有序訪問。作用域鏈的下一個變量對象則來自下一個包含環境。
前言
JavaScript中變量是松散類型,這樣它只在特定的時間內用于保存一個特定的值。由于不存在定義某個變量必須要保存何種數據類型的規則,變量的值和其數據類型可以在腳本的生命周期內改變。
1. 基本類型和引用類型的值JavaScript中變量可能包含兩種不同類型的值: 基本類型和引用類型。 基本類型值指的是簡單的數據段,而引用類型指的是那些可能多個值構成的對象。
JavaScript中有5種基本類型的值:Number, String, Null,Undefined, Boolean。這5種基本類型是按值訪問的,因為可以操作保存在變量中的實際的值。
引用類型的值是保存在內存中的對象。 與其他語言不同, JavaScript不允許直接訪問內存中的位置, 也就是說不能直接操作對象的內存空間。 在操作對象時, 實際上是操作對象的引用而不是實際的對象。因此,引用類型的值是按引用訪問的。
注意: 當復制保存著對象的某個變量時, 操作的是對象的引用。 但在為對象添加屬性的時候,操作的實際的對象
1.1 動態的屬性定義基本類型值和引用類型值得方式是類似的:創建一個變量并為該變量賦值。對于引用類型的值來說,我們可以為其添加屬性和方法,也可以改變和刪除其屬性和方法。但是基本類型的值卻不行。
var person = new Object() person.name = "Nicholas" alert(person.name) //"Nicholas"
如上,我們創建一個對象,并保存在person。然后為該對象添加一個name屬性,最后通過person.name可以訪問這個新屬性,如果對象不被銷毀或者這個屬性不被刪除,則這個屬性將一直存在。
如果我們給基本類型的值添加屬性,雖然不會導致錯誤,但是這樣是不合理的:
var name = "Nicholas" name.age = 27 alert(name.age) //undefined1.2 復制變量值
除了保存的方式不同,從一個變量向另一個變量復制基本類型值和引用類型值時也存在不同。如果一個變量向另一個變量復制基本類型的值,會在變量對象上創建一個新值,然后把該值復制到為新變量分配的位置上。
var num1 = 5 var num2 = num1
當從一個變量向另一個變量復制引用類型的值時,同樣也會將存儲在變量對象中的值復制一份放到為新變量分配的空間中。不同的是,這個值得副本實際上是一個指針,而這個指針指向存儲在堆中的一個對象。復制操作結束后,兩個變量實際上將引用同一個對象。因此,改變其中一個變量,就會影響另一個變量:
var o1 = new Object() var o2 = o2 o1.name = "Nicholas" alert(o2.name) //Nicholas1.3 傳遞參數
ECMAscript中所有的函數參數都是按值傳遞的,也就是說,把函數外部的值復制給函數內部參數,就和把值從一個變量復制到另一個變量一樣?;绢愋偷膫鬟f如同基本類型變量的復制一樣,而引用類型值得傳遞如何引用類型變量的復制一樣。
在向參數傳遞基本類型的值時,被傳遞的值會被復制給一個局部變量(即命名參數,就是arguments對象中的一個元素)。在向參數傳遞引用類型的值時,會把這個值在內存中的地址復制一個給局部變量,因此這個局部變量的變化會發生在外部。但是這樣總會感覺參數還是通過按引用傳遞的。下面這個例子可以證明是按值傳遞:
var person = new Object() function setName(obj) { obj.name = "Nicholas" obj = new Object() obj.name = "Greg" } setName(person)
如果person是按引用傳遞的,那么person會被改成一個新對象,但是當你繼續訪問person.name的時候返回的是"Nicholas"。這說明即使在函數內部修改了參數的值,但是原始的引用仍然保持未變。實際上當函數內部重寫obj時,這個變量引用的就是一個局部對象了,而這個局部對象會在函數執行完畢后銷毀。
2. 執行環境和作用域執行環境定義了變量或函數有權訪問的其他數據,決定了它們各自的行為。每個執行環境都有與之關聯的變量對象。執行環境中定義的所有變量和函數都保存在這個對象中。雖然我們編寫的代碼無法訪問這個對象,但解析器在處理數據時會在后臺使用它。
每個函數都有自己的執行環境,當執行流進入一個函數時,函數的環境就會被推入一個環境棧中,而在函數執行之后,棧將其環境彈出,把控制權返回給之前的執行環境。
當代碼在一個環境中執行時,會創建變量對象的一個作用域鏈,作用域鏈的用途,是保證對執行環境有權訪問的所有變量和函數的有序訪問。作用域鏈的前端,始終都是當前執行代碼所在的環境的變量對象。如果這個環境是函數,則將其活動對象作為變量對象?;顒訉ο笤谧铋_始時只包含一個變量,即argument對象。作用域鏈的下一個變量對象則來自下一個包含環境。這樣一直延續到全局環境。
標識符解析是沿著作用域鏈一級一級的搜索標識符的過程。
2.1 延長作用域鏈有些語句可以在作用域鏈的前端臨時增加一個變量對象, 該變量對象會在代碼執行后被移除。在兩種情況下會發生這種現象,具體來說就是當執行流進入下列任何一個語句時,作用域鏈會得到加長。
try-catch的catch塊
with語句
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/93046.html
前言 JavaScript中有一個被稱為作用域(Scope)的特性。雖然對于許多新手開發者來說,作用域的概念并不是很容易理解,本文我會盡我所能用最簡單的方式來解釋作用域和作用域鏈,希望大家有所收獲! 想閱讀更多優質文章請猛戳GitHub博客 作用域(Scope) 1.什么是作用域 作用域是在運行時代碼中的某些特定部分中變量,函數和對象的可訪問性。換句話說,作用域決定了代碼區塊中變量和其他資源的可見...
前言 JavaScript中有一個被稱為作用域(Scope)的特性。雖然對于許多新手開發者來說,作用域的概念并不是很容易理解,本文我會盡我所能用最簡單的方式來解釋作用域和作用域鏈,希望大家有所收獲! 想閱讀更多優質文章請猛戳GitHub博客 作用域(Scope) 1.什么是作用域 作用域是在運行時代碼中的某些特定部分中變量,函數和對象的可訪問性。換句話說,作用域決定了代碼區塊中變量和其他資源的可見...
摘要:一旦函數執行完成,其就會從作用域鏈頂部移除,并且執行權會返回到函數。攀爬作用域鏈當不同執行上下文之間存在變量命名沖突,可以通過攀爬作用域鏈解決從頂部到底部。 一、作用域 在 JavaScript 中, 作用域(scope,或譯有效范圍)就是變量和函數的可訪問范圍,即作用域控制著變量和函數的可見性和生命周期 二、全局/局部作用域 2.1 全局作用域(Global Scope) (1)不...
摘要:全局作用域局部作用域局部作用域全局作用域局部作用域塊語句沒有塊級作用域塊級聲明包括和,以及和循環,和函數不同,它們不會創建新的作用域。局部作用域只在該函數調用執行期間存在。 一、什么是作用域? 作用域是你的代碼在運行時,各個變量、函數和對象的可訪問性。(可產生作用的區域) 二、JavaScript中的作用域 在 JavaScript 中有兩種作用域 全局作用域 局部作用域 當變量定...
摘要:并且作用域鏈也確定了在當前上下文中查找標識符后返回的值。為了具象化分析問題,我們可以假設作用域鏈是一個數組,數組成員有一系列變量對象組成。注意,所有作用域鏈的最末端都為全局變量對象。所以作用域作用域鏈都是在當前運行環境內代碼執行前就確定了。 什么是作用域(Scope)? 作用域產生于程序源代碼中定義變量的區域,在程序編碼階段就確定了。javascript 中分為全局作用域(Global...
閱讀 2222·2021-09-24 10:31
閱讀 3875·2021-09-22 15:16
閱讀 3395·2021-09-22 10:02
閱讀 1010·2021-09-22 10:02
閱讀 1822·2021-09-08 09:36
閱讀 1974·2019-08-30 14:18
閱讀 609·2019-08-30 10:51
閱讀 1863·2019-08-29 11:08