摘要:因此我們可以說變量對象包含了活動(dòng)對象,活動(dòng)對象就是作用域鏈上正在被執(zhí)行和引用的變量對象。
看一下是知乎大神對于 js 執(zhí)行環(huán)境 活動(dòng)對象 變量對象 作用域鏈的解釋
假設(shè)在全局環(huán)境下定義了函數(shù)pub()和變量pubvar:
var pubvar = 1; function pub () { var pravar = 2; return pubvar + pravar; } alert(pub(2)); //調(diào)用pub()函數(shù)
當(dāng)代碼在一個(gè)環(huán)境中執(zhí)行時(shí),會(huì)創(chuàng)建變量對象的一個(gè)作用域鏈(scope chain),這個(gè)作用域鏈包含了全局環(huán)境的變量對象(執(zhí)行環(huán)境中定義的所有變量和函數(shù)都保存在這個(gè)對象中)并被保存在pub()函數(shù)內(nèi)部的scope屬性中。但是,當(dāng)我們打開瀏覽器的時(shí)候已經(jīng)存在了一個(gè)全局的執(zhí)行環(huán)境,這個(gè)全局的執(zhí)行環(huán)境屬于瀏覽器,JS里瀏覽器被稱為window對象,我們把這個(gè)環(huán)境叫做A環(huán)境,只要沒有關(guān)閉瀏覽器,A環(huán)境會(huì)一直存在下面會(huì)提到執(zhí)行環(huán)境什么時(shí)候會(huì)被創(chuàng)建。我們用色塊表示執(zhí)行環(huán)境,鏈條表示作用域鏈,作用域鏈上半部分是活動(dòng)對象區(qū)域,下半部分是變量對象區(qū)域,如下圖:
當(dāng)我們調(diào)用pub()函數(shù)的時(shí)候,會(huì)在全局執(zhí)行環(huán)境A中創(chuàng)建一個(gè)執(zhí)行環(huán)境B,沒錯(cuò),執(zhí)行環(huán)境如其名是在運(yùn)行和執(zhí)行代碼的時(shí)候才存在的,所以我們運(yùn)行瀏覽器的時(shí)候會(huì)創(chuàng)建全局的執(zhí)行環(huán)境。這個(gè)時(shí)候根據(jù)pub()函數(shù)scope屬性中的作用域鏈把pub()函數(shù)內(nèi)的變量對象放入新的B環(huán)境中,作用域鏈也得到更新,如下圖:
上圖的虛線表示正在執(zhí)行,全局變量對象此時(shí)處于作用域鏈的第二位所以標(biāo)號(hào)變成了1。你可能也注意到那個(gè)arguments對象,它是在函數(shù)被創(chuàng)建的時(shí)候就一直存在的,無需用戶創(chuàng)建。arguments對象保存的是函數(shù)圓括號(hào)內(nèi)定義的參數(shù),準(zhǔn)確來說保存的是參數(shù)的值,因這里我們沒有設(shè)置參數(shù),所以顯示未定義。此時(shí)我們把屬于B環(huán)境的變量對象(也就是pub()函數(shù)中的所有函數(shù)和變量)叫做活動(dòng)對象。因此我們可以說變量對象包含了活動(dòng)對象,活動(dòng)對象就是作用域鏈上正在被執(zhí)行和引用的變量對象。我們從活動(dòng)對象的名稱中也能看出 “執(zhí)行、運(yùn)行、激活” 等意味。你可以這樣理解,整個(gè)代碼的運(yùn)行總有一個(gè)起始的對象吧,不管這個(gè)起始是變量還是函數(shù),總要有一個(gè)稱呼,雖然我們把執(zhí)行環(huán)境中的變量和函數(shù)的總稱叫做變量對象,但這不能反映代碼的動(dòng)態(tài)性,為了區(qū)別于普通的變量對象,我們創(chuàng)造了活動(dòng)對象的概念。
我們把上面的代碼變成如下:
var pubvar = 1; function pub () { var pravar = 2; return pubvar + pravar; } var pubvar2 = 3; function pub2 () { var pravar = 2; return pubvar2 + pravar; } alert(pub(2)); //調(diào)用pub()函數(shù)
這個(gè)時(shí)候全局的作用于鏈和執(zhí)行環(huán)境如下
接著我們調(diào)用pub()函數(shù),執(zhí)行環(huán)境和作用域鏈如下:
你看沒有被調(diào)用的pub2()函數(shù)仍然只是閑著,甚至沒有被pub()函數(shù)在內(nèi)部引用。由于pub2()沒有參與整個(gè)pub()函數(shù)的調(diào)用過程,所以pub2()中不存在活動(dòng)對象,只有“處于靜止?fàn)顟B(tài)”的變量對象,當(dāng)然也沒有創(chuàng)建執(zhí)行環(huán)境(因?yàn)樗緵]執(zhí)行嘛)。
到這里就完了?也沒有,我們剛才也只是討論了兩個(gè)平行且毫不關(guān)聯(lián)的函數(shù)其中一個(gè)被調(diào)用的狀況,言下之意就是也存在函數(shù)相互影響的例子,最典型的就是閉包,閉包是一種函數(shù)嵌套的情況。定義如下代碼:
function returnfunc (propertyName) { return function (obj) { //-----這行定義并返回了一個(gè)閉包,也被稱之為一個(gè)匿名函數(shù) return obj[propertyName]; //這里用方括號(hào)法訪問屬性,因?yàn)閷傩允亲兞浚╮eturnfunc()函數(shù)的參數(shù)) }; } var savefunc = returnfunc("name"); //調(diào)用returnfunc() var result = savefunc({name:"Picasso"});//調(diào)用savefunc() alert(result); //返回字符串“Picasso”
最開始的執(zhí)行環(huán)境和作用域鏈
我們先開始調(diào)用returnfunc()函數(shù),馬上會(huì)創(chuàng)建一個(gè)包含returnfunc()變量對象的行環(huán)境,作用域鏈開始變化,如下圖:
圖的白色虛線表示執(zhí)行程序產(chǎn)生的效果,它可能表示的是返回一個(gè)結(jié)果、復(fù)制某種值、產(chǎn)生一個(gè)新物體、建立某種聯(lián)系等。
題外話:你會(huì)發(fā)現(xiàn)上圖的arguments參數(shù)的值和propertyName的值是一樣的,這是因?yàn)閍rguments保存的就是參數(shù),采用實(shí)時(shí)映射的方式與參數(shù)建立聯(lián)系,如果你在returnfunc()函數(shù)內(nèi)再加一個(gè)值為{name:"picasso"},名為obj的參數(shù),那么arguments的值變成[{name:"nicholas"},{name:picasso}],是的,你沒看錯(cuò),arguments是一個(gè)數(shù)組!??!
隨后returnfunc()函數(shù)會(huì)返回它內(nèi)部的匿名函數(shù),當(dāng)匿名函數(shù)被返回后,整個(gè)作用域鏈和執(zhí)行環(huán)境又發(fā)生了變化:
我們看到匿名函數(shù)(閉包)被添加到了最作用域鏈的最前端,returnfunc()的執(zhí)行環(huán)境被銷毀,但我們注意到returnfunc()函數(shù)的活動(dòng)對象仍然在被引用(匿名函數(shù)仍在訪問propertyName參數(shù)),因此returnfunc()函數(shù)的變量對象仍然在內(nèi)存中,成為活動(dòng)對象。這就是為什么匿名函數(shù)就能訪問returnfunc()函數(shù)定義的所有變量和全局環(huán)境定義的變量,畢竟returnfunc()的活動(dòng)對象仍然保持“激活”狀態(tài)。
根據(jù)上面所述,隨著代碼一行一行的被執(zhí)行、執(zhí)行環(huán)境不斷被創(chuàng)建和銷毀、變量對象間的各種關(guān)系被建立,這些背后的邏輯導(dǎo)致活動(dòng)對象也在不斷變化,這足以證明活動(dòng)對象只是正在被執(zhí)行和引用的變量對象。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/92808.html
摘要:至此作用域鏈創(chuàng)建完畢。好了,通過深入理解作用域鏈,我們能跟好的理解的運(yùn)行機(jī)制和閉包的原理。 前言 理解javascript中的作用域和作用域鏈對我們理解js這們語言。這次想深入的聊下關(guān)于js執(zhí)行的內(nèi)部機(jī)制,主要討論下,作用域,作用域鏈,閉包的概念。為了更好的理解這些東西,我模擬了當(dāng)一個(gè)函數(shù)執(zhí)行時(shí),js引擎做了哪些事情--那些我們看不見的動(dòng)作。 關(guān)鍵詞: 執(zhí)行環(huán)境 作用域 作用域鏈 變...
摘要:全局執(zhí)行環(huán)境的變量對象始終是作用域鏈中的最后一個(gè)變量對象。綜上,每個(gè)函數(shù)對應(yīng)一個(gè)執(zhí)行環(huán)境,每個(gè)執(zhí)行環(huán)境對應(yīng)一個(gè)變量對象,而多個(gè)變量對象構(gòu)成了作用域鏈,如果當(dāng)前執(zhí)行環(huán)境是函數(shù),那么其活動(dòng)對象在作用域鏈的前端。 1.幾個(gè)概念 先說幾個(gè)概念:函數(shù)、執(zhí)行環(huán)境、變量對象、作用域鏈、活動(dòng)對象。這幾個(gè)東東之間有什么關(guān)系呢,往下看~ 函數(shù) 函數(shù)大家都知道,我想說的是,js中,在函數(shù)內(nèi)部有兩個(gè)特殊...
摘要:下面我們就羅列閉包的幾個(gè)常見問題,從回答問題的角度來理解和定義你們心中的閉包。函數(shù)可以通過作用域鏈相互關(guān)聯(lián)起來,函數(shù)內(nèi)部的變量可以保存在其他函數(shù)作用域內(nèi),這種特性在計(jì)算機(jī)科學(xué)文獻(xiàn)中稱為閉包。 寫這篇文章之前,我對閉包的概念及原理模糊不清,一直以來都是以通俗的外層函數(shù)包裹內(nèi)層....來欺騙自己。并沒有說這種說法的對與錯(cuò),我只是不想擁有從眾心理或者也可以說如果我們說出更好更低層的東西,逼格...
摘要:所以,全局執(zhí)行環(huán)境的變量對象始終都是作用域鏈中的最后一個(gè)對象。講到這里,可能你已經(jīng)對執(zhí)行環(huán)境執(zhí)行環(huán)境對象變量對象作用域作用域鏈的理解已經(jīng)他們之間的關(guān)系有了一個(gè)較清晰的認(rèn)識(shí)。 JavaScript中的執(zhí)行環(huán)境、作用域、作用域鏈、閉包一直是一個(gè)非常有意思的話題,很多博主和大神都分享過相關(guān)的文章。這些知識(shí)點(diǎn)不僅比較抽象,不易理解,更重要的是與這些知識(shí)點(diǎn)相關(guān)的問題在面試中高頻出現(xiàn)。之前我也看過...
摘要:在作用域鏈中,外部函數(shù)的活動(dòng)對象始終處于第二位,外部函數(shù)的外部函數(shù)的活動(dòng)對象處于第三位,直到作用域鏈終點(diǎn)即全局執(zhí)行環(huán)境。更為重要的是函數(shù)在執(zhí)行完畢后,其他活動(dòng)對象也不會(huì)被銷毀,因?yàn)槟涿瘮?shù)的作用域鏈仍然在引用這個(gè)活動(dòng)對象。 原文鏈接----請點(diǎn)這里 ??閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù),創(chuàng)建閉包的常見方式,就是在一個(gè)函數(shù)內(nèi)部創(chuàng)建另一個(gè)函數(shù)。 ??之所以一個(gè)內(nèi)部的函數(shù)可以...
閱讀 1053·2021-11-15 18:11
閱讀 3175·2021-09-22 15:33
閱讀 3469·2021-09-01 11:42
閱讀 2663·2021-08-24 10:03
閱讀 3630·2021-07-29 13:50
閱讀 2932·2019-08-30 14:08
閱讀 1282·2019-08-28 17:56
閱讀 2266·2019-08-26 13:57