国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

JS學(xué)習(xí)系列 06 - 變量對(duì)象

Stardustsky / 365人閱讀

摘要:變量對(duì)象就是執(zhí)行上下文和作用域鏈中間的橋梁。作用域鏈和留到后面再講,今天我們先來(lái)弄明白變量對(duì)象。全局執(zhí)行上下文環(huán)境全局對(duì)象全局上下文環(huán)境的變量對(duì)象引用全局對(duì)象自身屬性作用域鏈舉個(gè)例子因此,在全局上下文環(huán)境中,變量對(duì)象用全局對(duì)象來(lái)表示。

上一節(jié)我們討論了執(zhí)行上下文,那么在上下文中到底有什么內(nèi)容,為什么它會(huì)和作用域鏈扯上關(guān)系,JS 解釋器又是怎么找到我們聲明的函數(shù)和變量,看完這一節(jié),相信大家就不會(huì)再迷惑了。

變量對(duì)象就是執(zhí)行上下文作用域鏈中間的橋梁。
劇透一下,神秘的 this 就存在于執(zhí)行上下文環(huán)境之中!
當(dāng)然,之后我會(huì)多帶帶用幾節(jié)來(lái)徹底講明白 this 到底是什么(其實(shí) this 很簡(jiǎn)單)。

接下來(lái),我們進(jìn)入正文。

1. 執(zhí)行上下文包含什么

一個(gè)執(zhí)行上下文我們可以抽象的理解為對(duì)象(object)。
每一個(gè)執(zhí)行上下文都有一些屬性(又稱(chēng)為上下文狀態(tài)),它們用來(lái)追蹤關(guān)聯(lián)代碼的執(zhí)行進(jìn)度。

我用一個(gè)結(jié)構(gòu)圖來(lái)說(shuō)明:

Variable Object 就代表變量對(duì)象。
Scope Chain 代表作用域鏈。
thisValue 代表神秘的 this 。

作用域鏈和 this 留到后面再講,今天我們先來(lái)弄明白變量對(duì)象

2. 變量對(duì)象
A variable object is a scope of data related with the execution context. It’s a special object associated with the context and which stores variables and function declarations are being defined within the context.

變量對(duì)象(variable object) 是與執(zhí)行上下文相關(guān)的數(shù)據(jù)作用域(scope of data) 。它是與上下文關(guān)聯(lián)的特殊對(duì)象,用于存儲(chǔ)被定義在上下文中的 變量(variables) 和 函數(shù)聲明(function declarations) 。

變量對(duì)象(Variable Object -- 簡(jiǎn)寫(xiě) VO)是一個(gè)抽象的概念,指代與執(zhí)行上下文相關(guān)的特殊對(duì)象,它存儲(chǔ)著在上下文中聲明的:

變量(var)

函數(shù)聲明 (function declaration,簡(jiǎn)寫(xiě) FD)

函數(shù)的形參(arguments)

我們假設(shè)變量對(duì)象為一個(gè)普通 ECMAScript 對(duì)象:

VO = {};

就像前面講過(guò)的,VO 是執(zhí)行上下文的一個(gè)屬性:

activeExecutionContext = {
  VO: {
    // 上下文數(shù)據(jù) (vars, FD, arguments)
  }
}

因?yàn)樽兞繉?duì)象是一個(gè)抽象的概念,所以并不能通過(guò)變量對(duì)象的名稱(chēng)直接訪問(wèn),但是卻可以通過(guò)別的方法來(lái)間接訪問(wèn)變量對(duì)象,例如在全局上下文環(huán)境的變量對(duì)象會(huì)有一個(gè)屬性 window (DOM 中) 可以引用變量對(duì)象自身,全局上下文環(huán)境的另一個(gè)屬性 this 也指向全局上下文環(huán)境的變量對(duì)象。

舉個(gè)例子:

var a = 2;

function foo (num) {
   var b = 5;
}

(function exp () {
   console.log(111);
})

foo(10);

這里對(duì)應(yīng)的變量對(duì)象是:

// 全局上下文環(huán)境的變量對(duì)象
VO(globalContext) = {
   // 一些全局環(huán)境初始化時(shí)系統(tǒng)自動(dòng)創(chuàng)建的屬性: Math、String、Date、parseInt等等
   ···

   // 全局上下文的變量對(duì)象中有一個(gè)屬性可以訪問(wèn)到自身,在瀏覽器中這個(gè)屬性是 window ,在 node 中這個(gè)屬性是 global
   window: global

   // 自己定義的屬性
   a: 10,
   foo: 
};

// foo 函數(shù)上下文的變量對(duì)象
VO(foo functionContext) = {
   num: 10,
   b: 5
};

注意:函數(shù)表達(dá)式并不包括在變量對(duì)象中。

3. 不同執(zhí)行上下文中的變量對(duì)象

執(zhí)行上下文包括:全局上下文、函數(shù)上下文和 eval() 上下文。

全局上下文中的變量對(duì)象

這里我們先來(lái)了解一下什么是全局對(duì)象:

全局對(duì)象(global object)是指在進(jìn)入任何執(zhí)行上下文之前就已經(jīng)創(chuàng)建了的對(duì)象。
這個(gè)對(duì)象只有一份,它的屬性在程序中的任何地方都可以訪問(wèn),全局對(duì)象的生命周期終止于程序退出的那一刻。

全局對(duì)象初始化時(shí)系統(tǒng)將創(chuàng)建并初始化一系列原始屬性,例如:Math、String、Date、parseInt、window等等,之后是我們?cè)谌稚舷挛闹凶约憾x的全局變量。在 DOM 中,全局對(duì)象的 window 屬性可以引用全局對(duì)象自身,全局上下文環(huán)境的 this 屬性也可以引用全局對(duì)象。

// 全局執(zhí)行上下文環(huán)境
EC(globalContext) = {
   // 全局對(duì)象(全局上下文環(huán)境的變量對(duì)象) 
   global: {
      Math: <...>,
      String: <...>,
      ...
      ...
      window: global     // 引用全局對(duì)象自身
   },
   
   // this 屬性
   this: global

   // 作用域鏈
   ...
}

舉個(gè)例子:

var a = 10;

console.log(a);               // 10
console.log(window.a);        // 10
console.log(this.a);          // 10

因此,在全局上下文環(huán)境中,變量對(duì)象用全局對(duì)象來(lái)表示。

函數(shù)上下文中的變量對(duì)象

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

VO(functionContext) = AO

活動(dòng)對(duì)象是在進(jìn)入函數(shù)上下文時(shí)刻被創(chuàng)建的,它是通過(guò)函數(shù)的 arguments 屬性進(jìn)行初始化。arguments 也是一個(gè)對(duì)象。

AO = {
   arguments: {
      ...
   }
}

arguments 是活動(dòng)對(duì)象的一個(gè)屬性,它也是一個(gè)對(duì)象,包括以下屬性:

callee - 指向當(dāng)前函數(shù)的引用

length - 真正傳遞的參數(shù)個(gè)數(shù)

properties-indexes - index 是字符串類(lèi)型的整數(shù),例如"1": "aa",類(lèi)似于數(shù)組類(lèi)型,也可以通過(guò)arguments[1]來(lái)訪問(wèn),但是不能用數(shù)組的方法(push, pop等等)。另外,properties-indexes 的值和實(shí)際傳遞進(jìn)來(lái)的參數(shù)之間是共享的,一個(gè)改變,另一個(gè)也隨之改變。

舉個(gè)例子:

function foo (x, y, z) {
  
   // 聲明的函數(shù)參數(shù)數(shù)量
   console.log(foo.length);      // 3

   // 實(shí)際傳遞進(jìn)來(lái)的參數(shù)數(shù)量
   console.log(arguments.length);      // 2

   // arguments 的 callee 屬性指向當(dāng)前函數(shù)
   console.log(arguments.callee === foo)   // true

   // 參數(shù)共享
   console.log(x === arguments[0]);      // true
   console.log(x);      // 10

   arguments[0] = 20;
   console.log(x);   // 20

   x = 30;
   console.log(arguments[0]);    // 30

   // 但是注意,沒(méi)有傳遞進(jìn)來(lái)的參數(shù) z ,和第3個(gè)索引值是不共享的
   z = 40;
   console.log(arguments[2]);      // undefined

   arguments[2] = 50;
   console.log(z);      // 40
}

foo(10, 20);
4. 代碼是如何被處理的

在第1節(jié)中我們講過(guò)js 代碼的編譯過(guò)程,其中有一步叫作預(yù)編譯,是說(shuō)在代碼執(zhí)行前的幾微秒會(huì)首先對(duì)代碼進(jìn)行編譯,形成詞法作用域,然后執(zhí)行。

那么執(zhí)行上下文的代碼就就可以分成兩個(gè)階段來(lái)處理:

進(jìn)入執(zhí)行上下文(預(yù)編譯)

執(zhí)行代碼

而變量對(duì)象的修改變化和這兩個(gè)階段是緊密相關(guān)的。
并且所有類(lèi)型的執(zhí)行上下文都會(huì)有這2個(gè)階段。

進(jìn)入執(zhí)行上下文

當(dāng)引擎進(jìn)入執(zhí)行上下文時(shí)(代碼還未執(zhí)行),VO 里已經(jīng)包含了一些屬性:

函數(shù)的所有形參(如果是函數(shù)執(zhí)行上下文)

由名稱(chēng)和對(duì)應(yīng)值組成的一個(gè)變量對(duì)象的屬性被創(chuàng)建,如果沒(méi)有傳遞對(duì)應(yīng)的實(shí)參,那么由名稱(chēng)和 undefined 組成的一種變量對(duì)象的屬性也會(huì)被創(chuàng)建。

所有的函數(shù)聲明(Function Declaration - FD)

由名稱(chēng)和對(duì)應(yīng)值(函數(shù)對(duì)象 function object)組成的一個(gè)變量對(duì)象的屬性被創(chuàng)建,如果變量對(duì)象已經(jīng)存在相同名稱(chēng)函數(shù)的屬性,則完全替換這個(gè)屬性。

所有的變量聲明(Variable Declaration - var)

由名稱(chēng)和對(duì)應(yīng)值(在預(yù)編譯階段所有變量值都是 undefined)組成的一個(gè)變量對(duì)象的屬性被創(chuàng)建,如果變量名和已經(jīng)聲明的形參或者函數(shù)相同,則變量名不會(huì)干擾已經(jīng)存在的這類(lèi)屬性,如果已經(jīng)存在相同的變量名,則跳過(guò)當(dāng)前聲明的變量名。

注意:變量碰到相同名稱(chēng)的變量是忽略,函數(shù)碰到相同名稱(chēng)的函數(shù)是覆蓋。

舉個(gè)例子:

function foo (a, b) {
   var c = 5;

   function bar () {};

   var d = function _d () {};

   (function f () {});
}

foo(10);

當(dāng)進(jìn)入帶有實(shí)參10的 foo 函數(shù)上下文時(shí)(預(yù)編譯時(shí),此時(shí)代碼還沒(méi)有執(zhí)行),AO 結(jié)構(gòu)如下:

AO(foo) = {
   a: 10,
   b: undefined,

   c: undefined,
   bar: ,
   d: undefined 
};

注意,函數(shù)表達(dá)式 f 并不包含在活動(dòng)對(duì)象 AO 內(nèi)。
也就是說(shuō),只有函數(shù)聲明會(huì)被包含在變量對(duì)象 VO 里面,函數(shù)表達(dá)式并不會(huì)影響變量對(duì)象。

行內(nèi)函數(shù)表達(dá)式 _d 則只能在該函數(shù)內(nèi)部可以使用, 也不會(huì)包含在 VO 內(nèi)。

這之后,就會(huì)進(jìn)入第2個(gè)階段,代碼執(zhí)行階段。

代碼執(zhí)行

在這個(gè)階段,AO/VO 已經(jīng)有了屬性(并不是所有的屬性都有值,大部分屬性的值還是系統(tǒng)默認(rèn)的初始值 undefined)。

AO 在代碼執(zhí)行階段被修改如下:

AO["c"] = 5;
AO["d"] = 

再次要提醒大家,因?yàn)楹瘮?shù)表達(dá)式 _d 已經(jīng)保存到了聲明的變量 d 上面,所以變量 d 仍然存在于 VO/AO 中。我們可以通 d() 來(lái)執(zhí)行函數(shù)。但是函數(shù)表達(dá)式 f 卻不存在于 VO/AO 中,也就是說(shuō),如果我們想嘗試調(diào)用 f 函數(shù),不管在函數(shù)定義前還是定義后,都會(huì)出現(xiàn)一個(gè)錯(cuò)誤"f is not defined",未保存的函數(shù)表達(dá)式只有在它自己的定義或遞歸中才能被調(diào)用。

再來(lái)一個(gè)經(jīng)典例子:

console.log(x);      // function

var x = 10;
console.log(x);      // 10

x = 20;

function x () {};

console.log(x);      // 20

這里為什么是這樣的結(jié)果呢?

上邊我們說(shuō)過(guò),在代碼執(zhí)行之前的預(yù)編譯,會(huì)為變量對(duì)象生成一些屬性,先是形參,再是函數(shù)聲明,最后是變量,并且變量并不會(huì)影響同名的函數(shù)聲明。

所以,在進(jìn)入執(zhí)行上下文時(shí),AO/VO 結(jié)構(gòu)如下:

AO = {
   x: 

   // 在碰到變量聲明 x 時(shí),因?yàn)橐呀?jīng)存在了函數(shù)聲明 x ,所以會(huì)忽略
}

緊接著,在代碼執(zhí)行階段,AO/VO 被修改如下:

AO["x"] = 10;
AO["x"] = 20;

希望大家可以好好理解變量對(duì)象,對(duì)于理解我們后邊要講的作用域鏈有很大的幫助。

5. 變量

有一些文章說(shuō)過(guò):

不管是使用 var 關(guān)鍵字(在全局上下文)還是不使用 var 關(guān)鍵字(在任何地方),都可以聲明一個(gè)變量。

請(qǐng)記住,這是錯(cuò)誤的觀念。

任何時(shí)候,變量都只能通過(guò)使用 var 關(guān)鍵字來(lái)聲明(ES6 之前)

a = 10;

上面的賦值語(yǔ)句,僅僅是給全局對(duì)象創(chuàng)建了一個(gè)新屬性(在在非嚴(yán)格模式,嚴(yán)格模式下會(huì)報(bào)錯(cuò)),但注意,它不是變量。“不是變量”并不是說(shuō)它不能被改變,而是指它不符合ECMAScript 規(guī)范中變量的概念。

讓我們通過(guò)一個(gè)例子來(lái)看一下兩者的區(qū)別:

console.log(a);        // undefined
console.log(b);        // 報(bào)錯(cuò),b is not defined

b = 10;
var a = 20;

只要我們很好的理解了:變量對(duì)象、預(yù)編譯階段和執(zhí)行代碼階段,就可以迅速的給出答案。

預(yù)編譯(進(jìn)入上下文)階段:

VO = {
   a: undefined
}

我們可以看到,因?yàn)?b 不是通過(guò) var 聲明的,所以這個(gè)階段根本就沒(méi)有 b ,b 只有在代碼執(zhí)行階段才會(huì)出現(xiàn)。但是在這個(gè)例子中,還沒(méi)有執(zhí)行到 b 那就已經(jīng)報(bào)錯(cuò)了。

我們稍微更改一下示例代碼:

console.log(a);      // undefined

b = 10;
console.log(b);             // 10 代碼執(zhí)行階段被創(chuàng)建
console.log(window.b);      // 10
console.log(this.b);        // 10

var a = 20;
console.log(a);      // 20 代碼執(zhí)行階段被修改

關(guān)于變量,還有一個(gè)很重要的知識(shí)點(diǎn)。

變量不能用 delete 操作符來(lái)刪除。

a = 10;

console.log(window.a);    // 10

console.log(delete a);    // true

console.log(window.a);    // undefined

var b = 20;
console.log(window.b);    // 20

console.log(delete b);    // false

console.log(window.b);    // 20

注意:這個(gè)規(guī)則在 eval() 上下文中不起作用。

eval("var a = 10;");
console.log(window.a);    // 10

console.log(delete a);    // true

console.log(window.a);    // undefined
6. 總結(jié)

這一節(jié)中我們講了變量對(duì)象,下一節(jié)就是我們的重頭戲 - 作用域鏈。希望大家可以持續(xù)關(guān)注我,我們一起進(jìn)步。

歡迎關(guān)注我的公眾號(hào)

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/81953.html

相關(guān)文章

  • Spring IOC 容器源碼分析系列文章導(dǎo)讀

    摘要:本文是容器源碼分析系列文章的第一篇文章,將會(huì)著重介紹的一些使用方法和特性,為后續(xù)的源碼分析文章做鋪墊。我們可以通過(guò)這兩個(gè)別名獲取到這個(gè)實(shí)例,比如下面的測(cè)試代碼測(cè)試結(jié)果如下本小節(jié),我們來(lái)了解一下這個(gè)特性。 1. 簡(jiǎn)介 Spring 是一個(gè)輕量級(jí)的企業(yè)級(jí)應(yīng)用開(kāi)發(fā)框架,于 2004 年由 Rod Johnson 發(fā)布了 1.0 版本。經(jīng)過(guò)十幾年的迭代,現(xiàn)在的 Spring 框架已經(jīng)非常成熟了...

    NSFish 評(píng)論0 收藏0
  • 聽(tīng)飛狐聊JavaScript設(shè)計(jì)模式系列06

    本回內(nèi)容介紹 上一回聊到JS中模擬接口,裝飾者模式,摻元類(lèi),分析了backbone的繼承源碼,感覺(jué)還好吧! 介一回,偶們來(lái)聊一下在JS單例模式(singleton),單例模式其實(shí)運(yùn)用很廣泛,比如:jquery,AngularJS,underscore吖蝦米的都是單例模式,來(lái)吧,直接開(kāi)始咯: 1. 單例模式 保證一個(gè)類(lèi)只有一個(gè)實(shí)例,從全局命名空間里提供一個(gè)唯一的訪問(wèn)點(diǎn)來(lái)訪問(wèn)該對(duì)象。其實(shí)之前寫(xiě)過(guò)的對(duì)象...

    hiYoHoo 評(píng)論0 收藏0
  • 【ES6腳丫系列】模塊Module

    摘要:命令用于規(guī)定本模塊的對(duì)外接口。空格模塊名字符串。其他模塊加載該模塊時(shí),命令可以為該匿名函數(shù)指定任意名字。寫(xiě)法函數(shù)聲明命令用在非匿名函數(shù)前,也是可以的。加載的時(shí)候,視同匿名函數(shù)加載。 本文字符數(shù)8200+,閱讀時(shí)間約16分鐘。 『ES6知識(shí)點(diǎn)總結(jié)』模塊Module 第一節(jié):Module基本概念 【01】過(guò)去使用CommonJS和AMD,前者用于服務(wù)器,后者用于瀏覽器。 Module可以取...

    gotham 評(píng)論0 收藏0
  • WebAssembly 系列(四)WebAssembly 工作原理

    摘要:但是它們其實(shí)并不是二選一的關(guān)系并不是只能用或者。正因?yàn)槿绱耍噶钣袝r(shí)也被稱(chēng)為虛擬指令。這是因?yàn)槭遣捎没跅5奶摂M機(jī)的機(jī)制。聲明模塊的全局變量。。下文預(yù)告現(xiàn)在你已經(jīng)了解了模塊的工作原理,下面將會(huì)介紹為什么運(yùn)行的更快。 作者:Lin Clark 編譯:胡子大哈 翻譯原文:http://huziketang.com/blog/posts/detail?postId=58c77641a6d8...

    stormzhang 評(píng)論0 收藏0
  • 前端培訓(xùn)-中級(jí)階段(8)- jQuery元素屬性樣式操作(2019-08-01期)

    摘要:前端最基礎(chǔ)的就是。對(duì)應(yīng),是標(biāo)簽的屬性。獲取匹配元素相對(duì)父元素的偏移。返回的對(duì)象包含兩個(gè)整型屬性和。一組包含作為動(dòng)畫(huà)屬性和終值的樣式屬性和及其值的集合動(dòng)畫(huà)的額外選項(xiàng)。指示是否在效果隊(duì)列中放置動(dòng)畫(huà)。 前端最基礎(chǔ)的就是 HTML+CSS+Javascript。掌握了這三門(mén)技術(shù)就算入門(mén),但也僅僅是入門(mén),現(xiàn)在前端開(kāi)發(fā)的定義已經(jīng)遠(yuǎn)遠(yuǎn)不止這些。前端小課堂(HTML/CSS/JS),本著提升技術(shù)水平,...

    everfly 評(píng)論0 收藏0

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

0條評(píng)論

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