摘要:當我將此題的作用域鏈畫出來之后,終于感覺作用域入門了。創建函數的作用域鏈,并初始化為函數的所包含的對象,即包含了的作用域鏈。
作用域
為了理解作用域,跪看了好幾篇大神的博文,終于略知一二。
1.題目其中,看到這樣一道題(稍作修改):
function factory() { var name = "laruence"; var intro = function(){ console.log("I am " + name); console.log("I am " + age + "years"); } return intro; } function app(para){ var name = para; var age = 20; var func = factory(); func(); } app("eve");
運行結果是:
I am laruence 腳本報錯:Uncaught ReferenceError: age is not defined
雖然在不理解作用域的情況下,我也做出了正確答案。但當我看了網上大神對作用域的講解后,再來看此題,越看越經典,當初能做對,純粹運氣。當我將此題的作用域鏈畫出來之后,終于感覺作用域入門了。
2.圖解作用域(1)JS引擎在進入一段可執行的代碼時,需要完成以下三個初始化工作:
創建一個全局對象(Global Object):全局對象在創建時,將Math,String,Date,document 等常用的JS對象作為其屬性。還有另外一個屬性window,將window指向了自身,這樣就可以通過window訪問這個全局對象了。
構建一個執行環境棧( Execution Context Stack):當執行一個函數時,該函數的執行環境就會被推入執行環境棧的頂部并獲取執行權。當這個函數執行完畢,它的執行環境又從這個棧的頂部被刪除,并把執行權并還給之前執行環境。
創建一個全局執行環境(Execution Context)EC,并將這個全局執行環境EC壓入執行環境棧中。
創建一個與EC關聯的全局變量對象(Varibale Object) VO,并把VO指向全局對象。VO中不僅包含了全局對象的原有屬性,還包括在全局定義的變量和函數。同時,在定義函數A的時候,還為 A 添加了一個內部屬性scope,并將scope指向了VO。每個函數在定義的時候,都會創建一個與之關聯的scope屬性,scope總是指向定義函數時所在的環境。
(2)當執行進入app("eve") 時
創建函數app的執行環境EC(a):然后EC(a)推入執行環境棧的頂部并獲取執行權。
創建函數app的作用域鏈(Scope Chain):在javascript中,每個執行環境都有自己的作用域鏈,用于標識符解析,當執行環境被創建時,它的作用域鏈就初始化為當前運行函數的scope所包含的對象。
創建一個當前函數的活動對象(Activation Object) AO:AO中包含了函數的形參、arguments對象、this對象、以及局部變量和內部函數的定義,然后AO會被推入作用域鏈的頂端。需要注意的是,在定義函數B的時候,JS引擎同樣也會為B添加了一個scope屬性,并將scope指向了定義函數B時所在的環境,定義函數B的環境就是A的活動對象AO, 而AO位于鏈表的前端,由于鏈表具有首尾相連的特點,因此函數B的scope指向了A的整個作用域鏈。
(3)當執行進入factory() 時
創建函數factory的執行環境EC(f):然后EC(f)推入執行環境棧的頂部并獲取執行權。
創建函數factory的作用域鏈Scope Chain(f):在javascript中,每個執行環境都有自己的作用域鏈,用于標識符解析,當執行環境被創建時,它的作用域鏈就初始化為當前運行函數的scope所包含的對象。
創建一個當前函數的活動對象AO(f):AO中包含了函數的形參、arguments對象、this對象、以及局部變量和內部函數的定義,然后AO(f)會被推入作用域鏈的頂端。需要注意的是,在定義函數intro的時候,JS引擎同樣也會為intro添加了一個scope屬性,并將scope指向了定義函數intro時所在的環境,定義函數intro的環境就是factory的活動對象AO(f), 而AO(f)位于鏈表的前端,由于鏈表具有首尾相連的特點,因此函數intro的scope指向了factory的整個作用域鏈。
(4)當執行進入func()時
函數factory被執行以后,返回了intro的引用,并賦值給了變量func,執行 func() 就相當于執行intro()。
創建函數intro的執行環境EC(i),然后EC(i)推入執行環境棧的頂部并獲取執行權。 此時執行環境棧中有三個執行環境,分別是全局執行環境、函數app的執行環境和函數intro,intro的執行環境在棧頂,全局執行環境在棧的底部。
創建函數intro的作用域鏈Scope Chain(i),并初始化為函數intro的scope所包含的對象,即包含了factory的作用域鏈。
創建函數intro的活動對象AO(i),并將intro的arguments對象和this對象作為AO(i)的屬性。
執行func()時,它的作用域鏈為 VO(G ) <- AO(f) <- AO(i),所以
讀取name屬性時,AO(i)對象上沒有name屬性,沿著作用域鏈到AO(f),讀取到了name屬性,值為"laruence";
讀取age屬性時,其實你會發現只有AO(f)上定義了age屬性,而AO(f)又不在作用域鏈上,所以此時會報腳本錯誤Uncaught ReferenceError: age is not defined,表示age屬性未定義。這也從側面證明了我們上面的作用域鏈分析是正確的。
執行完成,退出。
3.Javascript中的作用域JavaScript中的函數運行在它們被定義的作用域里,而不是它們被執行的作用域里。
在JS中,每次調用一個函數的時候 ,就會進入一個函數內的作用域,當從函數返回以后,就返回調用前的作用域。
在javascript中,每個函數都有自己的執行環境,當執行一個函數時,該函數的執行環境就會被推入執行環境棧的頂部并獲取執行權。當這個函數執行完畢,它的執行環境又從這個棧的頂部被刪除,并把執行權并還給之前執行環境。
每個函數在定義的時候,都會創建一個與之關聯的scope屬性,scope總是指向定義函數時所在的環境。
在javascript中,每個執行環境都有自己的作用域鏈,用于標識符解析,當執行環境被創建時,它的作用域鏈就初始化為當前運行函數的scope所包含的對象。
有了作用域鏈, 在發生標識符解析的時候, 就會逆向查詢當前scope chain列表的每一個活動對象的屬性,如果找到同名的就返回。找不到,那就是這個標識符沒有被定義。
全局對象(Global Object) , 這個對象全局只存在一份,它的屬性在任何地方都可以訪問,它的存在伴隨著應用程序的整個生命周期。全局對象在創建時,Math,String,Date,document 等常用的JS對象作為其屬性。
活動對象(Activation Object) AO,這里的活動對象扮演著變量對象的角色,只是在函數中的叫法不同而已(你可以認為變量對象是一個總的概念,而活動對象是它的一個分支), AO中包含了函數的形參、arguments對象、this對象、以及局部變量和內部函數的定義,然后AO會被推入作用域鏈的頂端。
參考文獻javascript 從定義到執行,你不知道的那些事
Javascript作用域原理
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/79009.html
摘要:一看這二逼就是周杰倫的死忠粉看看控制臺輸出,確實沒錯就是對象。從根本上來說,作用域是基于函數的,而執行環境是基于對象的例如全局執行環境即全局對象。全局對象全局屬性和函數可用于所有內建的對象。全局對象只是一個對象,而不是類。 覺得本人寫的不算很爛的話,可以登錄關注一下我的GitHub博客,博客會堅持寫下去。 今天同學去面試,做了兩道面試題,全部做錯了,發過來給我看,我一眼就看出來了,因為...
摘要:作用域與作用域鏈每個函數都有自己的執行環境。這是初步了解作用域,如想更深入了解作用域,請看下面鏈接作用域原理作用域鏈由一道題圖解的作用域或者看權威指南和高級程序設計 本文是我學習JavaScript作用域整理的筆記,如有不對,請多指出。 作用域 一個變量的作用域是程序源代碼中定義這個變量的區域。 而在ES5中只分為全局作用域和函數作用域,也就是說for,if,while等語句是不會創建...
摘要:中所有的事件綁定都是異步編程當前這件事件沒有徹底完成,不再等待,繼續執行下面的任務當綁定事件后,不需要等待執行,繼續執行下一個循環任務,所以當我們點擊執行方法的時候,循環早已結束即是最后。 概念 閉包就是指有權訪問另一個函數作用域中的變量的函數 點擊li標簽彈出對應數字 0 1...
摘要:和塊級作用域實際上為新增了塊級作用域。這表示外層代碼塊不受內層代碼塊的影響。塊級作用域的出現,實際上使得獲得廣泛應用的立即執行函數表達式不再必要了。其他騷氣方法參考阮老師并發模型與事件循環 沒有錯,這道題就是: for (var i = 0; i< 10; i++){ setTimeout(() => { console.log(i); }, 1000...
摘要:今天同學去面試,做了兩道面試題全部做錯了,發過來給道典型的面試題前端掘金在界中,開發人員的需求量一直居高不下。 排序算法 -- JavaScript 標準參考教程(alpha) - 前端 - 掘金來自《JavaScript 標準參考教程(alpha)》,by 阮一峰 目錄 冒泡排序 簡介 算法實現 選擇排序 簡介 算法實現 ... 圖例詳解那道 setTimeout 與循環閉包的經典面...
閱讀 3564·2023-04-26 00:05
閱讀 954·2021-11-11 16:55
閱讀 3523·2021-09-26 09:46
閱讀 3517·2019-08-30 15:56
閱讀 909·2019-08-30 15:55
閱讀 2934·2019-08-30 15:53
閱讀 1940·2019-08-29 17:11
閱讀 814·2019-08-29 16:52