首頁  >  文章  >  web前端  >  前端基礎進階變數物件詳解

前端基礎進階變數物件詳解

PHP中文网
PHP中文网原創
2017-06-20 09:50:551193瀏覽

開年之後工作熱情一直不太高,這幾天一直處於消極怠工狀態。早上不想起床,起床了不想上班。明明放假前工作熱情還一直很高,一直心心念念的想把小程式項目懟出來,結果休假回來之後畫風完全不一樣了。我感覺自己得了嚴重了節後症候群。還好擼了幾篇文章,勉強表示這一週的時間沒有完全浪費。這篇文章要跟大家介紹的是變數物件。 在JavaScript中,我們肯定不可避免的需要宣告變數和函數,可是JS解析器是如何找到這些變數的呢?我們也得對執行上下文有進一步的了解。 在上一篇文章中,我們已經知道,當一個函數被呼叫時(啟動),一個新的執行上下文就會被創建。而一個執行上下文的生命週期可以分成兩個階段。

  • 建立階段
    在這個階段中,執行上下文會分別建立變數對象,建立作用域鏈,以及決定this的指向

  • 程式碼執行階段
    建立完成之後,就會開始執行程式碼,這個時候,會完成變數賦值,函數引用,以及執行其他程式碼。


執行上下文生命週期

#從這裡我們可以看出詳細了解執行上下文極為重要,因為其中涉及了變數對象,作用域鏈,this等很多人沒有怎麼弄明白,但是卻極為重要的概念,因此它關係到我們能不能真正理解JavaScript。在後面的文章中我們會一一詳細總結,這裡我們先專注於了解變數物件。

變數物件(Variable Object)

變數物件的創建,依序經歷了以下幾個過程。

  1. 建立arguments物件。檢查目前上下文中的參數,建立該物件下的屬性與屬性值。

  2. 檢查目前上下文的函數聲明,也就是使用function關鍵字聲明的函數。在變數物件中以函數名建立一個屬性,屬性值為指向函數所在記憶體位址的參考。如果函數名的屬性已經存在,那麼該屬性將會被新的參考所覆寫。

  3. 檢查目前上下文中的變數聲明,每找到一個變數聲明,就在變數物件中以變數名稱建立屬性,屬性值為undefined。如果該變數名的屬性已經存在,為了防止同名的函數被修改為undefined,則會直接跳過,原屬性值不會被修改。


我知道有的人不喜歡看文字

根據這個規則,要理解變數提升就變得十分簡單了。在很多文章中雖然提到了變數提升,但是具體是怎麼回事還真的很多人都說不出來,以後在面試中用變數對象的創建過程跟面試官解釋變數提升,保證瞬間提升逼格。

在上面的規則中我們看出,function宣告會比var宣告優先權更高一點。為了幫助大家更好的理解變數對象,我們結合一些簡單的例子來進行探討。

// demo01function test() {console.log(a);console.log(foo());var a = 1;function foo() {return 2;
    }
}

test();

在上例中,我們直接從test()的執行上下文開始理解。當全域作用域中執行test()時,test()的執行上下文開始建立。為了方便理解,我們用如下的形式來表示

创建过程
testEC = {// 变量对象    VO: {},    scopeChain: {},    this: {}
}// 因为本文暂时不详细解释作用域链和this,所以把变量对象专门提出来说明// VO 为 Variable Object的缩写,即变量对象
VO = {    arguments: {...},  //注:在浏览器的展示中,函数的参数可能并不是放在arguments对象中,这里为了方便理解,我做了这样的处理    foo: <foo reference>  // 表示foo的地址引用    a: undefined
}

未進入執行階段之前,變數物件中的屬性都不能存取!但是進入執行階段之後,變數物件轉變為了活動對象,裡面的屬性都能被存取了,然後開始進行執行階段的操作。

這樣,如果再面試的時候被問到變數對象和活動對像有什麼區別,就又可以自如的應答了,他們其實都是同一個對象,只是處於執行上下文的不同生命週期。

// 执行阶段VO ->  AO   // Active ObjectAO = {
    arguments: {...},
    foo: <foo reference>,
    a: 1
}

因此,上面的例子demo1,執行順序就變成了這樣

function test() {function foo() {return 2;
    }var a;console.log(a);console.log(foo());
    a = 1;
}

test();

再來一個例子,鞏固一下我們的理解。

// demo2function test() {console.log(foo);console.log(bar);var foo = &#39;Hello&#39;;console.log(foo);var bar = function () {return &#39;world&#39;;
    }function foo() {return &#39;hello&#39;;
    }
}

test();
// 创建阶段VO = {
    arguments: {...},
    foo: <foo reference>,
    bar: undefined
}
// 这里有一个需要注意的地方,因为var声明的变量当遇到同名的属性时,会跳过而不会覆盖
// 执行阶段VO -> AOVO = {
    arguments: {...},
    foo: &#39;Hello&#39;,
    bar: <bar reference>
}

需要結合上面的知識,仔細對比這個例子中變數物件從創建階段到執行階段的變化,如果你已經理解了,說明變數物件相關的東西都已經難不倒你了。

全域上下文的變數物件

以瀏覽器中為例,全域物件為window。
全域上下文有一個特殊的地方,它的變數對象,就是window對象。而這個特殊,在this指向上也同樣適用,this也是指向window。

// 以浏览器中为例,全局对象为window// 全局上下文
windowEC = {
    VO: window,
    scopeChain: {},this: window
}

除此之外,全域上下文的生命週期,與程式的生命週期一致,只要程式運作不結束,例如關掉瀏覽器窗口,全域上下文就會一直存在。其他所有的上下文環境,都能直接存取全域上下文的屬性。

以上是前端基礎進階變數物件詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn