摘要:活動對象的變化與處理上下文的兩個階段密切相關。所有變量聲明由名稱和對應值組成一個變量對象的屬性被創建如果變量名稱跟已經聲明的形式參數或函數相同,則變量聲明不會干擾已經存在的這類屬性。
1 定義
如果變量與執行上下文相關,那變量自己應該知道它的數據存儲在哪里,并且知道如何訪問。這種機制稱為變量對象(variable object)。
變量對象(縮寫為VO)是一個與執行上下文相關的特殊對象,它存儲著在上下文中聲明的以下內容:
變量 (var, 變量聲明);
函數聲明 (FunctionDeclaration, 縮寫為FD);
函數的形參
舉例來說,我們可以用普通的ECMAScript對象來表示一個變量對象:
VO = {};
就像我們所說的, VO就是執行上下文的屬性(property):
activeExecutionContext = { VO: { // 上下文數據(var, FD, function arguments) } };2 全局上下文中的變量對象
全局上下文中的變量對象就是全局對象,所以我們聲明的變量都是全局對象的屬性。
3 函數上下文中的變量對象函數上下文中的變量對象由活動對象(AO)扮演。
活動對象的變化與處理上下文的兩個階段密切相關。進入執行上下文和執行代碼。
3.1 進入執行上下文當進入執行上下文(代碼執行之前)時,VO里已經包含了下列屬性:
1. 函數的所有形參(如果我們是在函數執行上下文中) 由名稱和對應值組成的一個變量對象的屬性被創建;沒有傳遞對應參數的話,那么由名稱和undefined值組成的一種變量對象的屬性也將被創建。 2. 所有函數聲明(FunctionDeclaration, FD) 由名稱和對應值(函數對象(function-object))組成一個變量對象的屬性被創建;如果變量對象已經存在相同名稱的屬性,則完全替換這個屬性。 3. 所有變量聲明(var, VariableDeclaration) 由名稱和對應值(undefined)組成一個變量對象的屬性被創建;如果變量名稱跟已經聲明的形式參數或函數相同,則變量聲明不會干擾已經存在的這類屬性。
也就是變量提升和var x = undefined 不會影響形參x的值,之后調用x指向的還是形參。
注意:進入執行上下文時,函數聲明和變量聲明都提前,但是變量聲明的值還都是undefined,而函數聲明的變量已經可以指向函數。變量聲明的優先級最低。
讓我們看一個例子:
function test(a, b) { var c = 10; function d() {} var e = function _e() {}; (function x() {}); } test(10); // call
當進入帶有參數10的test函數上下文時,AO表現為如下:
AO(test) = { a: 10, b: undefined, c: undefined, d:e: undefined };
注意,AO里并不包含函數“x”。這是因為“x” 是一個函數表達式(FunctionExpression, 縮寫為 FE) 而不是函數聲明,函數表達式不會影響VO。 不管怎樣,函數“_e” 同樣也是函數表達式,但是就像我們下面將看到的那樣,因為它分配給了變量 “e”,所以它可以通過名稱“e”來訪問。
3.2 代碼執行進入上下文階段,AO/VO已經擁有了屬性(不過,并不是所有的屬性都有值,大部分屬性的值還是系統默認的初始值undefined )。
還是前面那個例子, AO/VO在代碼執行期間被修改如下:
AO["c"] = 10; AO["e"] =;
另一個經典例子:
alert(x); // function var x = 10; alert(x); // 10 x = 20; function x() {}; alert(x); // 20
為什么第一個alert “x” 的返回值是function,而且它還是在“x” 聲明之前訪問的“x” 的?為什么不是10或20呢?因為,根據規范函數聲明是在當進入上下文時填入的; 同意周期,在進入上下文的時候還有一個變量聲明“x”,那么正如我們在上一個階段所說,變量聲明在順序上跟在函數聲明和形式參數聲明之后,而且在這個進入上下文階段,變量聲明不會干擾VO中已經存在的同名函數聲明或形式參數聲明,因此,在進入上下文時,VO的結構如下:
VO = {}; VO["x"] =// 找到var x = 10; // 如果function "x"沒有已經聲明的話 // 這時候"x"的值應該是undefined // 但是這個case里變量聲明沒有影響同名的function的值 VO["x"] = //緊接著,在執行代碼階段,VO做如下修改: VO["x"] = 10; VO["x"] = 20;
我們可以在第二、三個alert看到這個效果。
在下面的例子里我們可以再次看到,變量是在進入上下文階段放入VO中的。(因為,雖然else部分代碼永遠不會執行,但是不管怎樣,變量“b”仍然存在于VO中。)
if (true) { var a = 1; } else { var b = 2; } alert(a); // 1 alert(b); // undefined,不是b沒有聲明,而是b的值是undefined
本文絕大部分內容來自: http://dmitrysoshnikov.com/ec...
僅做少許修改
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/86610.html
摘要:理解了這句話,我們就可以來看閉包了閉包前面說過,函數可以訪問函數作用域鏈中的變量,但如果我們想在函數外訪問函數內卻不行了。 不管是閉包還是this關鍵字,都是困擾JS初學者的比較難懂的東西,如果你對它們的認識還不足夠清晰,那么現在就一起把它們掌握掉。還是那句話,我們從最基本的開始,建立起一個非常清晰的知識結構,好了,開始吧 ? 閉包 當然我們今天說的是javascript里的閉包。要學...
摘要:全局和上下文中的作用域鏈這里不一定很有趣,但必須要提示一下。全局上下文的作用域鏈僅包含全局對象。代碼的上下文與當前的調用上下文擁有同樣的作用域鏈。代碼執行時對作用域鏈的影響在中,在代碼執行階段有兩個聲明能修改作用域鏈。 1 定義 我們已經知道一個執行上下文中的數據(參數,變量,函數)作為屬性存儲在變量對象中。 也知道變量對象是在每次進入上下文是創建并填入初始值,值的更新出現在代碼執行階...
摘要:最后重點理解結論箭頭函數的,總是指向定義時所在的對象,而不是運行時所在的對象。輸出,箭頭函數不會綁定所以傳入指向無效。原因是,要徹底理解應該是建立在已經大致理解了中的執行上下文,作用域作用域鏈,閉包,變量對象,函數執行過程的基礎上。 本文共 2025 字,看完只需 8 分鐘 概述 前面的文章講解了 JavaScript 中的執行上下文,作用域,變量對象,this 的相關原理,但是我...
摘要:是完全的面向對象語言,它們通過類的形式組織函數和變量,使之不能脫離對象存在。而在基于原型的面向對象方式中,對象則是依靠構造器利用原型構造出來的。 JavaScript 函數式腳本語言特性以及其看似隨意的編寫風格,導致長期以來人們對這一門語言的誤解,即認為 JavaScript 不是一門面向對象的語言,或者只是部分具備一些面向對象的特征。本文將回歸面向對象本意,從對語言感悟的角度闡述為什...
溫馨提示:作者的爬坑記錄,對你等大神完全沒有價值,別在我這浪費生命 這一切,源于阮大神博文學習Javascript閉包(Closure)- 阮一峰中的一道思考題 //問題1: var name = The Window; var object = { name : My Object, getNameFunc : function(){ return function(){ ...
閱讀 1428·2021-11-22 15:24
閱讀 2519·2021-10-11 11:06
閱讀 2323·2021-10-09 09:45
閱讀 2525·2021-09-09 09:33
閱讀 634·2019-08-30 15:53
閱讀 1439·2019-08-30 12:48
閱讀 657·2019-08-29 13:47
閱讀 500·2019-08-26 18:27