成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

講清楚之 javascript 變量對(duì)象

jeffrey_up / 2691人閱讀

摘要:示例代碼執(zhí)行上下文創(chuàng)建階段在這個(gè)階段上下文對(duì)象會(huì)生成,并創(chuàng)建變量對(duì)象創(chuàng)建作用域鏈確定的指向。全局對(duì)象是作用域鏈的頭,還意味著在頂層代碼中聲明的所有變量都將成為全局對(duì)象的屬性。

變量對(duì)象

這一節(jié)聊一下變量對(duì)象。都是干貨(^▽?zhuān)?

變量對(duì)象是函數(shù)運(yùn)行時(shí)數(shù)據(jù)的集合,存儲(chǔ)了在上下文中定義的變量和函數(shù),不同的函數(shù)的變量對(duì)象稍有不同。

還是從上下文說(shuō)起,javascript 引擎執(zhí)行到函數(shù)的時(shí)候會(huì)向上下文棧中壓入一個(gè)上下文。
上下文中包含:

name -
變量對(duì)象(VO, variable object) 當(dāng)前函數(shù)定義的變量、函數(shù)、參數(shù)
作用域鏈(Scope chain) 源代碼定義時(shí)形成的作用域鏈
this

偽代碼:

// 全局上下文的偽代碼
windowEC = {
    VO: Window,
    scopeChain: {},
    this: Window
}

作用域鏈為當(dāng)前函數(shù)提供上層可訪(fǎng)問(wèn)變量和函數(shù)的有序集合;

this為函數(shù)提供運(yùn)行時(shí)對(duì)象環(huán)境;

變量對(duì)象提供當(dāng)前函數(shù)定義時(shí)的變量和函數(shù);

上下文生成時(shí)包含的作用域鏈的形成,和this的指向原則在前面的章節(jié)已經(jīng)梳理過(guò)。
javascript 中主要有全局上下文、函數(shù)上下文。先了解一下函數(shù)調(diào)用時(shí)上下文棧的變化。

上下文棧狀態(tài)

當(dāng)函數(shù)被調(diào)用的時(shí)候,一個(gè)新的上下文會(huì)被加入到上下文棧的頂部, 而后會(huì)運(yùn)行函數(shù)內(nèi)部的代碼塊。

所以一個(gè)執(zhí)行上下文或者說(shuō)函數(shù)的生命周期分為上下文創(chuàng)建階段、函數(shù)運(yùn)行階段,不同階段上下文棧狀態(tài)和變量對(duì)象屬性會(huì)不一樣。

示例代碼:

function foo (a) {
    var b = 1
    function c () {
        console.log(a + b) // 100
    }
    c()
}
foo(99)
執(zhí)行上下文創(chuàng)建階段

在這個(gè)階段上下文對(duì)象會(huì)生成,并創(chuàng)建變量對(duì)象、創(chuàng)建作用域鏈、確定 this 的指向。

說(shuō)一千道一萬(wàn)還不如來(lái)張圖干脆。

foo 函數(shù)上下文創(chuàng)建完成后的棧狀態(tài)示意圖:

注意:此時(shí)函數(shù)內(nèi)表達(dá)式和語(yǔ)句未執(zhí)行,變量對(duì)象屬性值是根據(jù)規(guī)則被設(shè)置為初始值的。

運(yùn)行階段

上下文生成完成后,進(jìn)入函數(shù)運(yùn)行階段。依次按照代碼順序執(zhí)行函數(shù)內(nèi)代碼(變量的賦值、表達(dá)式計(jì)算、語(yǔ)句的執(zhí)行,其他函數(shù)調(diào)用等)。

在該階段會(huì)訪(fǎng)問(wèn)或設(shè)置變量對(duì)象(活動(dòng)對(duì)象)屬性的值。當(dāng)執(zhí)行完 foo 函數(shù)內(nèi)第一行代碼var b = 1,此時(shí)棧狀態(tài):

以此類(lèi)推,每次函數(shù)表達(dá)式執(zhí)行時(shí)都會(huì)在執(zhí)行上下文長(zhǎng)中獲取標(biāo)識(shí)符的值,通過(guò)運(yùn)算后又將結(jié)果保存在指定的標(biāo)識(shí)符里。因此執(zhí)行上下文為函數(shù)提供一個(gè)類(lèi)似于寄存器的概念來(lái)管理數(shù)據(jù)的功能。

當(dāng)函數(shù)執(zhí)行完后,對(duì)應(yīng)的執(zhí)行上下文被銷(xiāo)毀。JavaScript 執(zhí)行器會(huì)返回父函數(shù)或依據(jù)源代碼順序跳轉(zhuǎn)到其他函數(shù)。

函數(shù)上下文

在函數(shù)上下文中,我們用活動(dòng)對(duì)象(activation object, AO)來(lái)表示變量對(duì)象。

活動(dòng)對(duì)象和變量對(duì)象其實(shí)是一個(gè)東西,只是變量對(duì)象是規(guī)范上的或者說(shuō)是引擎實(shí)現(xiàn)上的,不可在 JavaScript 環(huán)境中訪(fǎng)問(wèn),只有到當(dāng)進(jìn)入一個(gè)執(zhí)行上下文中,這個(gè)執(zhí)行上下文的變量對(duì)象才會(huì)被激活,所以才叫 activation object ,而只有被激活的變量對(duì)象,也就是活動(dòng)對(duì)象上的各種屬性才能被訪(fǎng)問(wèn)。

活動(dòng)對(duì)象也是在進(jìn)入函數(shù)上下文時(shí)刻被創(chuàng)建的,活動(dòng)對(duì)象變量對(duì)象的一種激活狀態(tài)。所以當(dāng)你把變量對(duì)象活動(dòng)對(duì)象記混淆了不要緊,因?yàn)樗麄儽举|(zhì)上對(duì)我們理解函數(shù)調(diào)用時(shí)的細(xì)節(jié)沒(méi)有影響。我在大多數(shù)時(shí)候也直接用變量對(duì)象來(lái)表述。

變量對(duì)象的創(chuàng)建

變量對(duì)象的創(chuàng)建主要是進(jìn)行標(biāo)識(shí)符值類(lèi)型的申明和初始化,遵從下面這3條原則:

生成 arguments 對(duì)象。檢查當(dāng)前上下文的形參,生成屬性與屬性值對(duì)象(key: value)

當(dāng)形參沒(méi)有被賦值時(shí), 屬性值被設(shè)置為 undefined

在變量對(duì)象上建立函數(shù)索引。檢查當(dāng)前作用域定義的 function,在變量對(duì)象中以函數(shù)名為 key, 以函數(shù)所在內(nèi)存地址為 value 建立索引。

如果函數(shù)名已經(jīng)在變量對(duì)象中,則該函數(shù)名對(duì)應(yīng)的函數(shù)會(huì)被新的函數(shù)替換。所以函數(shù)可以被重復(fù)定義,后定義的函數(shù)會(huì)覆蓋掉先前定義的。

申明變量。檢查當(dāng)前作用域定義的變量,在變量對(duì)象中以變量名為 key, 以 undefined 為值掛載內(nèi)部變量。

如果新申明的變量名與已經(jīng)申明的形參名、函數(shù)名相同,則申明會(huì)被拋棄。

所以需要注意的是函數(shù)申明比變量申明優(yōu)先級(jí)高,一旦函數(shù)申明占用了某一個(gè)標(biāo)識(shí)符,后續(xù)的變量申明如果使用的是先前使用過(guò)的函數(shù)標(biāo)識(shí)符, 則該變量申明無(wú)效。

栗子1:

function foo () {
    function too() {
    }
    var too
    console.log(typeof too)
}
foo()
// function
// 變量 too 的申明無(wú)效

我們把上面的栗子稍作修改, 栗子2:

function foo () {
    function too() {
    }
    var too = 1
    console.log(typeof too)
}
foo()
// number
// 變量 too 的值類(lèi)型為 number

變量 too 的值類(lèi)型為 number, 看到這個(gè)栗子大家可能會(huì)疑惑, 因?yàn)楦鶕?jù)上面的3條規(guī)則, too 的第二次申明應(yīng)該是無(wú)效的且 too 的類(lèi)型應(yīng)該為 function。 其實(shí) too 的值類(lèi)型在上下文創(chuàng)建階段確實(shí)是 function, 由于 javascript 是動(dòng)態(tài)弱類(lèi)型語(yǔ)言, 在上下文執(zhí)行階段 var too = 1 實(shí)質(zhì)是在給 too 賦值并且發(fā)生了隱式類(lèi)型轉(zhuǎn)換, 所以在執(zhí)行階段 too 變成了 number 類(lèi)型。es6 語(yǔ)法中已經(jīng)不建議使用var 來(lái)申明變量了, 而是使用let 來(lái)申明局部變量,從語(yǔ)法層面強(qiáng)制避免了重復(fù)的變量申明, 這樣栗子2中的情況會(huì)直接報(bào)錯(cuò)。

將上面的栗子再次修改,進(jìn)一步探索:

function foo () {
    function too() {
    }
    console.log(typeof too) // function
    var too = 1
    console.log(typeof too) // number
}
foo()

foo 函數(shù)運(yùn)行時(shí)會(huì)先打印 ‘function’,然后打印 ‘number’。首先表達(dá)式console.log(typeof too)執(zhí)行時(shí)標(biāo)識(shí)符too在上下文創(chuàng)建階段被初始化為一個(gè)函數(shù)。var too = 1執(zhí)行后標(biāo)識(shí)符too被賦值為 1,所以第二次console.log(typeof too)的時(shí)候輸出的是number.

再再舉一個(gè)例子:

function foo () {
    console.log(a)
    console.log(bar)
    var a = 1
    function bar() {
        return 2
    }
}
foo()
// undefind
// ? bar() {
//      return 2
//  }

上下文創(chuàng)建階段解析函數(shù)內(nèi)代碼塊后,會(huì)在變量對(duì)象上添加 ‘a(chǎn)’, ‘bar’ 兩個(gè)標(biāo)識(shí)符,并填充相應(yīng)的值結(jié)束上下文的創(chuàng)建階段進(jìn)入foo 函數(shù)的執(zhí)行階段。

在執(zhí)行階段 foo 函數(shù)體第一行表達(dá)式要求打印輸出 a 的值, 由于 console.log(a) 之前沒(méi)有對(duì) a 進(jìn)行任何賦值操作,根據(jù)規(guī)則此時(shí) a 的值為 undefind 所以輸出 "undefind"。函數(shù)體內(nèi)第二行要求打印輸出 bar 的值,根據(jù)規(guī)則標(biāo)識(shí)符 "bar" 對(duì)應(yīng)的是函數(shù),所以 "bar" 的值為函數(shù)實(shí)體,且在 console.log(bar) 之前也未對(duì) bar 做賦值操作,所以打印出來(lái)的是該函數(shù)。

變量對(duì)象創(chuàng)建完,函數(shù)運(yùn)行前的變量對(duì)象是這樣的:

// VO 為 Variable Object的縮寫(xiě),即變量對(duì)象
VO = {
    arguments: {...},
    bar:   // 表示bar的地址引用
    a: undefined
}

變量對(duì)象(活動(dòng)對(duì)象)的創(chuàng)建過(guò)程實(shí)質(zhì)上就是我們經(jīng)常提起的函數(shù)變量提升,這里3條原則才是變量提升的本質(zhì)。

如果沒(méi)有理解透徹可以回頭看看前面的內(nèi)容。

全局上下文

在瀏覽器中,全局對(duì)象就是 window ,也是瀏覽器提供的預(yù)定義變量對(duì)象,可以通過(guò) thisself 引用。全局對(duì)象提供瀏覽器預(yù)置對(duì)象 Array、Object、console.log、alert 等,全局上下文的生命周期和函數(shù)的生命周期一樣,只要程序運(yùn)行不結(jié)束全局上下文就一直存在。其他所有的上下文環(huán)境,都能直接訪(fǎng)問(wèn)全局上下文的屬性。

全局對(duì)象是預(yù)定義的對(duì)象,作為 JavaScript 的全局函數(shù)和全局屬性的占位符。通過(guò)使用全局對(duì)象,可以訪(fǎng)問(wèn)所有其他所有預(yù)定義的對(duì)象、函數(shù)和屬性。在頂層 JavaScript 代碼中,可以用關(guān)鍵字 this 引用全局對(duì)象。因?yàn)槿謱?duì)象是作用域鏈的頭(最外層作用域),這意味著所有非限定性的變量和函數(shù)名都會(huì)作為該對(duì)象的屬性來(lái)查詢(xún)。例如,當(dāng)JavaScript 代碼引用 parseInt() 函數(shù)時(shí),它引用的是全局對(duì)象的 parseInt 屬性。全局對(duì)象是作用域鏈的頭,還意味著在頂層 JavaScript 代碼中聲明的所有變量都將成為全局對(duì)象的屬性。

通過(guò)this、seif訪(fǎng)問(wèn)全局對(duì)象:

console.log(this)
console.log(self)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/107802.html

相關(guān)文章

  • 講清楚之 javascript 參數(shù)傳值

    摘要:講清楚之參數(shù)傳值參數(shù)傳值是指函數(shù)調(diào)用時(shí),給函數(shù)傳遞配置或運(yùn)行參數(shù)的行為,包括通過(guò)進(jìn)行傳值。所以對(duì)的賦值會(huì)改變上下文棧中標(biāo)識(shí)符保存的具體值此時(shí)如果使用的是按引用傳遞,則變量所指向的對(duì)象因該也被賦值為。 講清楚之 javascript 參數(shù)傳值 參數(shù)傳值是指函數(shù)調(diào)用時(shí),給函數(shù)傳遞配置或運(yùn)行參數(shù)的行為,包括通過(guò)call、apply 進(jìn)行傳值。 在實(shí)際開(kāi)發(fā)中,我們總結(jié)javascript參數(shù)傳...

    itvincent 評(píng)論0 收藏0
  • 講清楚之執(zhí)行上下文

    摘要:棧底為全局上下文,棧頂為當(dāng)前正在執(zhí)行的上下文。位于棧頂?shù)纳舷挛膱?zhí)行完畢后會(huì)自動(dòng)出棧,依次向下直至所有上下文運(yùn)行完畢,最后瀏覽器關(guān)閉時(shí)全局上下文被銷(xiāo)毀。 講清楚之執(zhí)行上下文 標(biāo)簽 : javascript 什么是執(zhí)行上下文? 當(dāng) JavaScript 代碼執(zhí)行一段可執(zhí)行代碼時(shí),會(huì)創(chuàng)建對(duì)應(yīng)的上下文(execution context)并將該上下文壓入上下文棧(context stack...

    3fuyu 評(píng)論0 收藏0
  • 講清楚之 javascript原形

    摘要:構(gòu)造函數(shù)和實(shí)例都通過(guò)屬性指向了原形。代碼示例是構(gòu)造函數(shù)的實(shí)例的屬性與的屬性保存的值相等,即他們指向同一個(gè)對(duì)象原形。 講清楚之javascript原型 標(biāo)簽: javascript javascript 中原形是一個(gè)比較難于理解的概念。javascript 權(quán)威指南在原形這一章也花了大量的篇幅進(jìn)行介紹,也許你已經(jīng)讀過(guò)javascript 權(quán)威指南,或者已經(jīng)是讀第N篇了,然而這篇文章的目...

    高勝山 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<