Javascript深層原理探討(進(jìn)階版本)_第1頁(yè)
Javascript深層原理探討(進(jìn)階版本)_第2頁(yè)
Javascript深層原理探討(進(jìn)階版本)_第3頁(yè)
Javascript深層原理探討(進(jìn)階版本)_第4頁(yè)
Javascript深層原理探討(進(jìn)階版本)_第5頁(yè)
已閱讀5頁(yè),還剩17頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、tnksus&-原始值和引用值在 ECMAScript 中,變量可以存放兩種類型的值,即原始值和引用值。原始值指的就是代表原始數(shù)據(jù)類型(基本數(shù)據(jù)類型)的值,即 Undefined,Null,Number,String,Boolean 類型所表示的值。引用值指的就是復(fù)合數(shù)據(jù)類型的值,即 Object,Function,Array,以及自定義對(duì)象,等等棧和堆與原始值與引用值對(duì)應(yīng)存在兩種結(jié)構(gòu)的內(nèi)存即棧和堆原始值是存儲(chǔ)在棧中的簡(jiǎn)單數(shù)據(jù)段,也就是說(shuō),他們的值直接存儲(chǔ)在變量訪問(wèn)的位置。堆是存放數(shù)據(jù)的基于散列算法的數(shù)據(jù)結(jié)構(gòu),在 JavaScript 中,引用值是存放在堆中的。變量 num,bol,s

2、tr 為基本數(shù)據(jù)類型,它們的值,直接存放在棧中,obj,person,arr 為復(fù)合數(shù)據(jù)類型,他們的引用變量存儲(chǔ)在棧中,指向于存儲(chǔ)在堆中的實(shí)際對(duì)象。我們無(wú)法直接操縱堆中的數(shù)據(jù),也就是說(shuō)我們無(wú)法直接操縱對(duì)象,但我們可以通過(guò)棧中對(duì)對(duì)象的引用來(lái)操作對(duì)象。堆比棧大,棧比堆的運(yùn)算速度快,對(duì)象是一個(gè)復(fù)雜的結(jié)構(gòu),并且可以自由擴(kuò)展,如:數(shù)組可以無(wú)限擴(kuò)充,對(duì)象可以自由添加屬性。將他們放在堆中是為了不影響棧的效率。而是通過(guò)引用的方式查找到堆中的實(shí)際對(duì)象再進(jìn)行操作。相對(duì)于簡(jiǎn)單數(shù)據(jù)類型而言,簡(jiǎn)單數(shù)據(jù)類型就比較穩(wěn)定,并且它只占據(jù)很小的內(nèi)存。不將簡(jiǎn)單數(shù)據(jù)類型放在堆是因?yàn)橥ㄟ^(guò)引用到堆中查找實(shí)際對(duì)象是要花費(fèi)時(shí)間的,而這個(gè)綜合

3、成本遠(yuǎn)大于直接從棧中取得實(shí)際值的成本。所以簡(jiǎn)單數(shù)據(jù)類型的值直接存放在棧中。Null和Undefined的比較在 ECMAScript 的原始類型中,是有 Undefined 和 Null 類型的。這兩種類型都分別對(duì)應(yīng)了屬于自己的唯一專用值,即 undefined 和nullo 值 undefined 實(shí)際上是從值 null 派生來(lái)的,因此 ECMAScript 把它們定義為相等的。盡管這兩個(gè)值相等,但它們的含義不同。undefined 是聲明了變量但未對(duì)其初始化時(shí)賦予該變量的值,null 則用于表示尚未存在的對(duì)象。Udefined 代表沒(méi)有賦值的基本數(shù)據(jù)類型,Null 代表沒(méi)有賦值的引用數(shù)據(jù)類

4、型。null 參與數(shù)值運(yùn)算時(shí)其值會(huì)自動(dòng)轉(zhuǎn)換為 0,undefined 參與任何數(shù)值計(jì)算時(shí),其結(jié)果一定是 NaN。當(dāng)聲明的變量未初始化時(shí),該變量的默認(rèn)值是 undefined,但是 undefined 并不同于未定義的值。Typeof 運(yùn)算符無(wú)法區(qū)分這兩種值,因此對(duì)于變量是否存在的判斷操作是通過(guò) if(typeofvar=,undefined?)/codehere來(lái)進(jìn)行判斷的,這樣既完全兼容未定義(undefined)和未初始化(uninitialized)兩種情況的。f-rM 思傳球於薜LinksusMediaCummunicatiunGroupJavaScript全局觀1.核心(ECMASc

5、ript):定義了腳本語(yǔ)言的所有對(duì)象,屬性和方法。2.文檔對(duì)象模型(DOM):HTML 和 XML 應(yīng)用程序接口。3.瀏覽器對(duì)象模型(BOM):對(duì)瀏覽器窗口進(jìn)行訪問(wèn)操作。關(guān)于ECMAScript1.ECMAScript 是一種由歐洲計(jì)算機(jī)制造商協(xié)會(huì)(ECMA)通過(guò) ECMA-262 標(biāo)準(zhǔn)化的腳本程序設(shè)計(jì)語(yǔ)言。2.ECMAScript 的工作是定義語(yǔ)法和對(duì)象,從最基本的語(yǔ)法、數(shù)據(jù)類型、條件語(yǔ)句、關(guān)鍵字、保留字到異常處理和對(duì)象定義都是它的范疇。3.JavaScript 實(shí)現(xiàn)了 ECMAScript,AdobeActionScript 和 OpenViewScriptEase 同樣也實(shí)現(xiàn)了 ECMA

6、Script4.在 ECMAScript 范疇內(nèi)定義的對(duì)象也叫做原生對(duì)象,如 Object、Array、Function 等等。5.由 ECMA-262 定義的 ECMAScript 與 Web 瀏覽器沒(méi)有依賴關(guān)系。其實(shí)上它就是一套定義了語(yǔ)法規(guī)則的接口,然后由不同的瀏覽器對(duì)其進(jìn)行實(shí)現(xiàn),最后我們輸寫(xiě)遵守語(yǔ)法規(guī)則的程序,完成應(yīng)用開(kāi)發(fā)需求。關(guān)于DOM文檔對(duì)象模型(DocumentObjectModel)定義了訪問(wèn)和處理文檔的標(biāo)準(zhǔn)方法。根據(jù) DOM 的定義(HTML 和 XML 應(yīng)用程序接口)可知 DOM 由兩個(gè)部分組成:1.針又 XML 的 DOM 即 DOMCore2.針又 HTML 的 DOMH

7、TML。DOMCore 的核心概念就是節(jié)點(diǎn)(Node)。DOM 會(huì)將文檔中不同類型的元素(這里的元素并不特指這種 tag,還包括屬性,注釋,文本之類)都看作為不同的節(jié)點(diǎn)。DOMCORE 在解析文檔時(shí),會(huì)將所有的元素、屬性、文本、注釋等等視為一個(gè)節(jié)點(diǎn)對(duì)象(或繼承自節(jié)點(diǎn)對(duì)象的對(duì)象,多態(tài)、向上轉(zhuǎn)型),根據(jù)文本結(jié)構(gòu)依次展現(xiàn),最后行成了一棵DOM 樹(shù)DOMHTML 的核心概念是 HTMLElement,DOMHTML 會(huì)將文檔中的元素(這里的元素特指這種 tag,不包括注釋,屬性,文本)都視為HTMLElement。而元素的屬性,則為 HTMLElement 的屬性。其實(shí)上 DOMCore 和 DOMh

8、tml 的外部調(diào)用接口相差并不是很大,對(duì)于 html 文檔可以用 DOMhtml 進(jìn)行操作,針對(duì) Xhtml 可以用 DOMCore。JavaScriptDOM 模型示例:關(guān)于BOMBOM 解析:1. BOM 是 browserobjectmodel 的縮寫(xiě),簡(jiǎn)稱瀏覽器對(duì)象模型2. BOM 提供了獨(dú)立于內(nèi)容而與瀏覽器窗口進(jìn)行交互的對(duì)象3. 由于 BOM 主要用于管理窗口與窗口之間的通訊,因此其核心對(duì)象是 window4. BOM 由一系列相關(guān)的對(duì)象構(gòu)成,并且每個(gè)對(duì)象都提供了很多方法與屬性BOM 模型示例:IikupkKidlinksusW基本的數(shù)據(jù)類型基本的數(shù)據(jù)類型與基本數(shù)據(jù)類型”的概念不一樣

9、:1 .”基本的數(shù)據(jù)類型指的是最常用的數(shù)據(jù)類型2 .”基本數(shù)據(jù)類型指的是原始類型(儲(chǔ)存在內(nèi)存中的方式)(-)原始類型(簡(jiǎn)單數(shù)據(jù)類型、基本數(shù)據(jù)類型)Undefined 類型:表示聲明了變量但未對(duì)其初始化時(shí)賦予該變量的值。undefined 為 Undefined 類型下的唯一的一個(gè)值。Null 類型:用于表示尚未存在的對(duì)象。Null 類型下也只有一個(gè)專用值 null。Boolean 類型:有兩個(gè)值 true 和 false,主要用于條件判斷,控制執(zhí)行流程。Number 類型:代表數(shù)字(即包括 32 的整數(shù),也包括 64 位的浮點(diǎn)數(shù))String 類型:用于代表字符串。(二)對(duì)象一個(gè)無(wú)序?qū)傩缘募?/p>

10、,這些屬性的值為簡(jiǎn)單數(shù)據(jù)類型、對(duì)象或者函數(shù)。這里對(duì)象并不特指全局對(duì)象 Object.(三)函數(shù)函數(shù)是對(duì)象的一種,實(shí)現(xiàn)上內(nèi)部屬性Class值為Function,表明它是函數(shù)類型。除了對(duì)象的內(nèi)部屬性方法外,還有Construct、Call、Scope等內(nèi)部屬性。函數(shù)作為函數(shù)調(diào)用與構(gòu)造器(使用 new 關(guān)鍵字創(chuàng)建實(shí)例對(duì)象)的處理機(jī)制不一樣(Function 對(duì)象除外)。內(nèi)部方法Construct用于實(shí)現(xiàn)作為構(gòu)造器的邏輯,方法Call實(shí)現(xiàn)作為函數(shù)調(diào)用的邏輯。這里的函數(shù)并不特指全局對(duì)象 Function。內(nèi)置數(shù)據(jù)類型(內(nèi)置對(duì)象)Function:函數(shù)類型的用戶接口。Object:對(duì)象類型的用戶接口。Bo

11、olean,Number,String:分別為這三種簡(jiǎn)單數(shù)值類型的對(duì)象包裝器,對(duì)象包裝在概念上有點(diǎn)類似 C#/Java 中的 Box/Unbox。Date,Array,RegExp:可以把它們看作是幾種內(nèi)置的擴(kuò)展數(shù)據(jù)類型。注:1.它們都是 JavaScript 語(yǔ)言的內(nèi)置對(duì)象,都可以看作是函數(shù)的派生類型,在這個(gè)意義上,可將它們跟用戶自定義的函數(shù)等同看待。2.它們各自可以代表一種數(shù)據(jù)類型,是暴露給開(kāi)發(fā)者對(duì)這些內(nèi)置數(shù)據(jù)類型進(jìn)行操作的接口。在這個(gè)意義上,它們都是一種抽象的概念,后面隱藏了具體的實(shí)現(xiàn)機(jī)制。數(shù)據(jù)類型實(shí)現(xiàn)模型描述DataStructureImplementationModel標(biāo)準(zhǔn)注解:Bu

12、ild-in*datastructure:指 JS 內(nèi)部用于實(shí)現(xiàn)*類型的數(shù)據(jù)結(jié)構(gòu),由宿主環(huán)境(瀏覽器)提供,這些結(jié)構(gòu)我們基本上無(wú)法直接操作。Build-in*object:指 JS 內(nèi)置的 Number,String,Boolean 等這些對(duì)象,這是 JS 將內(nèi)部實(shí)現(xiàn)的數(shù)據(jù)類型暴露給開(kāi)發(fā)者使用的接口。Build-in*constructor:指 JS 內(nèi)置的一些構(gòu)造器,用來(lái)構(gòu)造相應(yīng)類型的對(duì)象實(shí)例。它們被包裝成函數(shù)對(duì)象暴露出來(lái)可理解:datastructure:存儲(chǔ)在內(nèi)存中的數(shù)據(jù)object:對(duì)于存儲(chǔ)在內(nèi)存中的數(shù)據(jù)的一種包裝(也存放在內(nèi)存中),提供各種接口以供程序語(yǔ)言對(duì)存儲(chǔ)在內(nèi)存中的數(shù)據(jù)進(jìn)行操作

13、。constructor:將存儲(chǔ)在內(nèi)存中的數(shù)據(jù)包裝的方法。關(guān)于簡(jiǎn)單數(shù)據(jù)類型的對(duì)象化一個(gè)細(xì)微的地方,下面描述對(duì)于 Boolean,String 和 Number 這三種簡(jiǎn)單數(shù)值類型都適用,以 Number 為例說(shuō)明。JS 規(guī)范要求:使用 varnum1=123;這樣的代碼,直接返回基本數(shù)據(jù)類型,就是說(shuō)返回的對(duì)象不是派生自 Number 和 Object 類型,用 num1instancEuil:-yUndefineddataeuciurs1國(guó)舊EuilS-inNumberNumber5 5L Ld-inStringStringdataslructLreda:astruciureAABuikJ-i

14、rrHumberconstrudor9inU*:nStringcoratnjctorA5uid-undefinedobjectBmid-jnBooleanBooleandata/UGirEABw3eanHuikknBooleancomtructar15sBuild-inBooleanobjectSu:ld-inObjectObjectdata5trucTuneFMDGtiQTBuik-irFurxlioncortstixictor=u=uj-nArraEArraEJil2-irRegEtpRegEtpsat35trucLr&tla:astructureBulo-inObjectettj

15、ectEuild-inFuncHonEJ J;J-inOaleobjectobje-ctIr-追1Builu-inArrayB BL Ld-:nRegEpcbjettobjectEjilc-inNaNdata5-riJcureRuk-inumberLril-inStringctjertotjectobiectEuils-inFun-ctionBulkkifiDateja:a?trjcur&darasinjctirseuiid-inObjectconLstrucIflr9u9dinDateconstructorBbil( (jConstruct等屬性應(yīng)當(dāng)為 null 或者內(nèi)部初始化值,即

16、我們可以理解為不指向任何對(duì)象(對(duì)Prototype這樣的屬性而言),或者不包含任何處理(對(duì)Call、Construct這樣的方法而言)。從上面的處理步驟可以了解,任何時(shí)候我們定義一個(gè)函數(shù),它的 prototype 是一個(gè) Object 實(shí)例,這樣默認(rèn)情況下我們創(chuàng)建自定義函數(shù)的實(shí)例對(duì)象時(shí),它們的 Prototype 鏈將指向 Ototype。函數(shù)對(duì)象構(gòu)造過(guò)程的分析functionAnimal();和 vardog=newAnimal();上述兩行簡(jiǎn)單的語(yǔ)句的實(shí)際構(gòu)造過(guò)程可以等價(jià)于以下的代碼:functionAnimal();等價(jià)于:Atotype=constr

17、uctor:Animal;vardog=(varo=;totype=Animal.Prototype;Animal.call(o);Returno;)();FunctionMObject關(guān)系Function 與 Object 可以總結(jié)為下圖:藍(lán)色線為類的 constructor 的實(shí)例橙色線為類的實(shí)例綠色線為類的 prototype 的實(shí)例黑色線為類的 constructor 的 prototype 的實(shí)例一所兩口。已討constructor/產(chǎn)*prototype,、A、-X%.f/4rL.+.汨 Xinstanceofconstructorprototypex*/canstrii

18、ctonprototypeObjectyfJ/*4*1J由上圖可以得出下列結(jié)論:1.Function 和 Object各為自身的實(shí)例。2.Object 是通過(guò) Function 進(jìn)行構(gòu)造的,而 Function 則由自己構(gòu)造自己。3.Function 的原型對(duì)象是 Object 的實(shí)例。關(guān)于Fuction與Object的總結(jié):Function函數(shù)就是對(duì)象,代表函數(shù)的對(duì)象就是函數(shù)對(duì)象。所有的函數(shù)對(duì)象是被 Function 這個(gè)函數(shù)對(duì)象構(gòu)造出來(lái)的。也就是說(shuō),Function 是最頂層的構(gòu)造器。它構(gòu)造了系統(tǒng)中所有的對(duì)象,包括用戶自定義對(duì)象,系統(tǒng)內(nèi)置對(duì)象,甚至包括它自已。這也表明Function具有自

19、舉性(自已構(gòu)造自己的能力)。這也間接決定了 Function 的call和constructor邏輯相同。Object對(duì)于 Object 它是最頂層的對(duì)象,所有的對(duì)象都將繼承 Object 的原型,Object 也是一個(gè)函數(shù)對(duì)象,Object 是被Function 構(gòu)造出來(lái)的。對(duì)象模型JavaScript 的對(duì)象模型如下圖所示:(紅色虛線表示隱式 Prototype 鏈)JavaScriptObjectModel總結(jié):1,圖中有好幾個(gè)地方提到 build-inFunctionconstructor,這是同一個(gè)對(duì)象,這說(shuō)明了幾個(gè)問(wèn)題:Function 指向系統(tǒng)內(nèi)置的函數(shù)構(gòu)造器(build-inF

20、unctionconstructor);Function 具有自舉性;系統(tǒng)中所有函數(shù)都是由 Function 構(gòu)造。2,左下角的 objl,obj2.objn 范指用類似這樣的7ft 碼創(chuàng)建的對(duì)象:functionfn1();varobj1=newfn1();這些對(duì)象沒(méi)有本地constructor 方法,但它們將從 Prototype 鏈上得到一個(gè)繼承的 constructor 方法,即 totype.constructor,從函數(shù)對(duì)象的構(gòu)造過(guò)程可以知道,它就是 fn 本身了。3,右下角的 obj1,obj2.objn 范指用類似這樣的代碼創(chuàng)建的對(duì)象:varobj1=newObje

21、ct();或 varobj1=;或 varobj1=newNumber(123);或 obj1=/w+/;等等。所以這些對(duì)象 Prototype 鏈的指向、從 Prototype 鏈繼承而來(lái)的 constructor 的值(指它們的 constructor 是build-inNumberconstructor 還是 build-inObjectconstructor 等)等依賴于具體的對(duì)象類型。另外注意的是,varobj=newObject(123);這樣創(chuàng)建的對(duì)象,它的類型仍然是 Number,即同樣需要根據(jù)參數(shù)值的類型來(lái)確定。同樣它們也沒(méi)有本地 constructor,而是從 Protot

22、ype 鏈上獲得繼承的 constructor 方法,即 build-in*constructor,具體是哪個(gè)由數(shù)據(jù)類型確定。4,Ototype 是整個(gè)鏈的終結(jié)點(diǎn),它的內(nèi)部Prototype為 null。5,所有函數(shù)的 Prototype 鏈都指向 Ftotype。這是規(guī)范要求的,因?yàn)樵O(shè)計(jì)者將 Function 設(shè)計(jì)為具有自舉性。6,Ftotype 的 Prototype 鏈指向 Ototype,這也是規(guī)范強(qiáng)制要求的。保證 Prototype 鏈只有唯一的一個(gè)終結(jié)點(diǎn)。7,因?yàn)?Ftotype

23、是一個(gè)函數(shù)對(duì)象,所以它應(yīng)當(dāng)具有顯示的 prototype 屬性,即 Ftotype,但只有FireFox 中可以訪問(wèn)到。8,用戶自定義函數(shù)(userdefinedfunctions)默認(rèn)情況下Prototype值是 Ototype,即它的隱式 Prototype 鏈指向Ototype,所以圖中就這樣表示了,但并不代表總是這樣,當(dāng)用戶設(shè)置了自定義函數(shù)的 prototype 屬性之后,情況就不同了。functionccrttrydor亂5fSwbocciniTuctotjitt-nCHbietoomfruorusecor

24、SmcErITCifi5N-kimlMCiSlnrig.RegExpccwi?yct0rJ*bu*-rFuTKtionH愉tr”班Kr”.,F(xiàn)umcbOHMHSfriidoro*biecttfiloreaseabya,小=門(mén)射3將ebieatm此中后恥fbyuwr:!fuF心蠟才flinctiona-員忠再抵黜病LinksusMediaCommunicatiunGroup屬性訪問(wèn)原則使用 pName 訪問(wèn)一個(gè)對(duì)象的屬性時(shí),按照下面的步驟進(jìn)行處理(假設(shè) obj 的內(nèi)部Prototype屬性名為_(kāi)proto_):1 .如果 obj 存在 propName 屬性,返回屬性的值,否則2

25、.如果 obj._proto_為null,返回 undefined,否貝 U3 .返回 obj._proto_.propName調(diào)用對(duì)象的方法跟訪問(wèn)屬性搜索過(guò)程一樣,因?yàn)榉椒ǖ暮瘮?shù)對(duì)象就是對(duì)象的一個(gè)屬性值。提示:上面步驟中隱含了遞歸過(guò)程,步驟 3 中 to是另外一個(gè)對(duì)象,同樣將采用 1,2,3 這樣的步 4II 來(lái)搜索 propName 屬性。這就是基于 Prototype 的繼承和共享:(object1 的方法 fn2 來(lái)自 object2,概念上即 object2 重寫(xiě)了 object3 的方法 fn2本地屬性與繼承屬性看一下設(shè)置對(duì)象屬性時(shí)的處理過(guò)程,pName

26、=value 的賦值語(yǔ)句處理步驟如下:1 .如果 propName 的 attribute 設(shè)置為不能設(shè)值,則返回2 .如果 pName 不存在,則為 obj 創(chuàng)建一個(gè)屬 T 名稱為 propName3 .將 pName 的值設(shè)為 value可以看到,設(shè)值過(guò)程并不會(huì)考慮 Prototype 鏈,對(duì)象的屬性無(wú)法修改其原型中的同名屬性,而只會(huì)自身創(chuàng)建一個(gè)同名屬性并為其賦值。道理很明顯,對(duì)象通過(guò)隱式 Prototype 鏈能夠?qū)崿F(xiàn)屬性和方法的繼承,但 prototype 也是一個(gè)普通對(duì)象,就是說(shuō)它是一個(gè)普通的實(shí)例化的對(duì)象,而不是純粹抽象的數(shù)據(jù)結(jié)構(gòu)描述。所以就有了這個(gè)本地屬

27、性與繼承屬性的問(wèn)題。obj 的內(nèi)部Prototype是一個(gè)實(shí)例化的對(duì)象,它不僅僅向 obj 共享屬性,還可能向其它對(duì)象共享屬性,修改它可能影響其它對(duì)象。linksuslinksusW執(zhí)行模型Javascript 執(zhí)行模型指的是一段 javascript 腳本從載入瀏覽器到顯示執(zhí)行都經(jīng)過(guò)了哪些流程。Javascript 執(zhí)行模型可簡(jiǎn)要總結(jié)如下:1.stepl.讀入第一個(gè)代碼段2.step2.做語(yǔ)法分析,有錯(cuò)則報(bào)語(yǔ)法錯(cuò)誤(比如括號(hào)不匹配等),并跳轉(zhuǎn)到 step53.step3.創(chuàng)建全局執(zhí)行環(huán)境(對(duì) var 變量和 function 定義做預(yù)解析)4.step4.執(zhí)行代碼段(調(diào)用函數(shù)、進(jìn)入 eval

28、 時(shí),都會(huì)創(chuàng)建新的執(zhí)行環(huán)境),有錯(cuò)則報(bào)錯(cuò)(比如變量未定義)5.step5.如果還有下一個(gè)代碼段,則讀入下一個(gè)代碼段,重復(fù) step26.step6.結(jié)束執(zhí)行環(huán)境(ExecutionContext)所有 JavaScript 代碼都是在一個(gè)執(zhí)行環(huán)境中被執(zhí)行的。它是一個(gè)概念,一種機(jī)制,用來(lái)完成 JavaScript 運(yùn)行時(shí)作用域、生存期等方面的處理。可執(zhí)彳 t 的 JavaScript 代碼分三種類型:1.GlobalCode,即全局的、不在任何函數(shù)里面的代碼,例如:一個(gè) js 文件、嵌入在 HTML 頁(yè)面中的 js 代碼等。2.EvalCode,即使用 eval()函數(shù)動(dòng)態(tài)執(zhí)行的 JS 代碼。3

29、.FunctionCode,即用戶自定義函數(shù)中的函數(shù)體 JS 代碼。不同類型的 JavaScript 代碼具有不同的 ExecutionContext。在一個(gè)頁(yè)面中,第一次載入 JS 代碼時(shí)創(chuàng)建一個(gè)全局執(zhí)彳 t 環(huán)境,當(dāng)調(diào)用一個(gè) JavaScript 函數(shù)時(shí),該函數(shù)就會(huì)進(jìn)入相應(yīng)的執(zhí)行環(huán)境。如果又調(diào)用了另外一個(gè)函數(shù)(或者遞歸地調(diào)用同一個(gè)函數(shù)),則又會(huì)創(chuàng)建一個(gè)新的執(zhí)行環(huán)境,并且在函數(shù)調(diào)用期間執(zhí)行過(guò)程都處于該環(huán)境中。當(dāng)調(diào)用的函數(shù)返回后,執(zhí)行過(guò)程會(huì)返回原始執(zhí)行環(huán)境。因而,運(yùn)行中的 JavaScript 代碼就構(gòu)成了一個(gè)執(zhí)行環(huán)境棧。程序在進(jìn)入每個(gè)執(zhí)行環(huán)境的時(shí)候都會(huì)創(chuàng)建一個(gè)叫做 VariableObjec

30、t 的對(duì)象。針對(duì)于函數(shù)執(zhí)行環(huán)境,函數(shù)對(duì)應(yīng)的每一個(gè)參數(shù)、局部變量、內(nèi)部方法都會(huì)在 VariableObject 上創(chuàng)建一個(gè)屬性,屬性名為變量名,屬性值為變量值。針對(duì)于全局執(zhí)行環(huán)境,具有相同的行為。但是要強(qiáng)調(diào)的一點(diǎn)是在全局執(zhí)行環(huán)境中 VaribleObject 就是 GlobalObject,可以簡(jiǎn)單白理解為 window 對(duì)象。全局執(zhí)行環(huán)境在一個(gè)頁(yè)面中,第一次載入 JS 代碼時(shí)創(chuàng)建一個(gè)全局執(zhí)行環(huán)境,全局執(zhí)行環(huán)境的作用域鏈實(shí)際上只由一個(gè)對(duì)象,即全局對(duì)象(window),在開(kāi)始 JavaScript 代碼的執(zhí)行之前,引擎會(huì)創(chuàng)建好這個(gè) ScopeChain 結(jié)構(gòu)。全局執(zhí)行環(huán)境也會(huì)有變量實(shí)例化的過(guò)程,它

31、的內(nèi)部函數(shù)就是涉及大部分JavaScript 代碼的、常規(guī)的頂級(jí)函數(shù)聲明。而且,在變量實(shí)例化過(guò)程中全局對(duì)象就是可變對(duì)象,這就是為什么全局性聲明的函數(shù)是全局對(duì)象屬性的原因。全局性聲明的變量同樣如此全局執(zhí)行環(huán)境會(huì)使用 this 對(duì)象來(lái)引用全局對(duì)象。Eval執(zhí)行環(huán)境構(gòu)建 Eval 執(zhí)行環(huán)境時(shí)白可變對(duì)象(VariableObject)就是調(diào)用 eval 時(shí)當(dāng)前執(zhí)行上下文中的可變對(duì)象(VariableObject)。在全局執(zhí)行環(huán)境中調(diào)用 eval 函數(shù),它的可變對(duì)象(VariableObject)就是全局對(duì)象;在函數(shù)中調(diào)用 eval,它的可變對(duì)象(VariableObject)就是函數(shù)的活動(dòng)對(duì)象(Act

32、ivationObject)。eval 調(diào)用中可以訪問(wèn)函數(shù) fn 的參數(shù)、局部變量;在 eval 中定義的局部變量在函數(shù) fn 中也可以訪問(wèn),因?yàn)樗鼈兊?VaribleObject 是同一個(gè)對(duì)象。進(jìn)入 EvalCode 執(zhí)行時(shí)會(huì)創(chuàng)建一個(gè)新的 ScopeChain,內(nèi)容與當(dāng)前執(zhí)行上下文的 ScopeChain 完全一樣。函數(shù)執(zhí)行環(huán)境在創(chuàng)建執(zhí)行環(huán)境的過(guò)程中,會(huì)按照定義的先后順序完成一系列操作:1.首先會(huì)創(chuàng)建一個(gè)活動(dòng)對(duì)象(ActivationObject)。活動(dòng)對(duì)象是規(guī)范中規(guī)定的另外一種機(jī)制。之所以稱之為對(duì)象,是因?yàn)樗鼡碛锌稍L問(wèn)的命名屬性,但是它又不像正常對(duì)象那樣具有原型(至少?zèng)]有預(yù)定義的原型),而

33、且不能通過(guò) JavaScript 代碼直接引用活動(dòng)對(duì)象。2.為函數(shù)調(diào)用創(chuàng)建執(zhí)行環(huán)境的下一步是創(chuàng)建一個(gè) arguments 對(duì)象,這是一個(gè)類似數(shù)組的對(duì)象,它以整數(shù)索引的數(shù)組成員一一對(duì)應(yīng)地保存著調(diào)用函數(shù)時(shí)所傳遞的參數(shù)。這個(gè)對(duì)象也有 length 和 callee 屬性。然后,會(huì)為活動(dòng)對(duì)象創(chuàng)建一個(gè)名為arguments”的屬性,該屬性引用前面創(chuàng)建的 arguments 對(duì)象。3.接著,為執(zhí)行環(huán)境分配作用域。作用域由對(duì)象列表(鏈)組成。4.之后會(huì)發(fā)生由 ECMA262 中所謂活動(dòng)對(duì)象完成的變量實(shí)例化(VariableInstatiation)的過(guò)程。此時(shí)會(huì)將函數(shù)的形式參數(shù)創(chuàng)建為可變對(duì)象的命名屬性,如果

34、調(diào)用函數(shù)時(shí)傳遞的參數(shù)與形式參數(shù)一致,則將相應(yīng)參數(shù)的值賦給這些命名屬性(否則,會(huì)給命名屬性賦 undefined 值)。對(duì)于定義的內(nèi)部函數(shù),會(huì)以其聲明時(shí)所用名稱為可變對(duì)象創(chuàng)建同名屬性,而相應(yīng)的內(nèi)部函數(shù)則被創(chuàng)建為函數(shù)對(duì)象并指定給該屬性。變量實(shí)例化的最后一步是將在函數(shù)內(nèi)部聲明的所有局部變量創(chuàng)建為可變對(duì)象的命名屬性。注:在這個(gè)過(guò)程中,除了實(shí)際參數(shù)有值外和函數(shù)定義外,其它都被預(yù)解析為 undefined 值.5.最后,要為使用 this 關(guān)鍵字而賦值。(此時(shí)的 this 指向的是全局對(duì)象,即 window)關(guān)于作用域和作用域鏈在訪問(wèn)變量時(shí),就必須存在一個(gè)可見(jiàn)性的問(wèn)題,這就是作用域(Scope)。更深入的

35、說(shuō),當(dāng)訪問(wèn)一個(gè)變量或調(diào)用一個(gè)函數(shù)時(shí),JavaScript 引擎將不同執(zhí)彳 t 位置上的 VariableObject 按照規(guī)則構(gòu)建一個(gè)鏈表,在訪問(wèn)一個(gè)變量時(shí),先在鏈表的第一個(gè) VariableObject 上查找,如果沒(méi)有找到則繼 2茅在第二個(gè) VariableObject 上查找,直到搜索結(jié)束。這也就形成了作用域鏈(ScopeChain)的概念。首先 ScopeChain 是一個(gè)類似鏈表/堆棧的結(jié)構(gòu),里面每個(gè)元素基本都是 VariableObject/ActivationObject。VariableObject 也叫做 ActivationObject(因?yàn)橛幸恍┎町惔嬖?,所以?guī)范中重新取

36、一個(gè)名字以示區(qū)別,GlobalCode/EvalCode 中叫 VariableObject,FunctionCode 中就叫做 ActivationObject)。每次進(jìn)入函數(shù)執(zhí)行都會(huì)創(chuàng)建一個(gè)新的 ActivationObject 對(duì)象,然后創(chuàng)建一個(gè) arguments 對(duì)象并設(shè)置為ActivationObject 的屬性,再進(jìn)行 VariableInstantiation 處理。在退出函數(shù)時(shí),ActivationObject 會(huì)被丟棄(并不是內(nèi)存釋放,只是可以被垃圾回收了)。執(zhí)行環(huán)境棧和作用域鏈的關(guān)系示例:functionFn1()functionFn2()alert(document.b

37、ody.tagName);/BODY/othercode.Fn2();執(zhí)行環(huán)境棧this關(guān)鍵字處理GlobalCode 中 this 關(guān)鍵字為 GlobalObject;函數(shù)調(diào)用時(shí) this 關(guān)鍵字為調(diào)用者,例如 obj1.fn1(),在 fn1 中 this 對(duì)象為 obj1;EvalCode 中 this 關(guān)鍵字為當(dāng)前執(zhí)行上下文的 VariableObject。在函數(shù)調(diào)用時(shí),JavaScript 提供一個(gè)讓用戶自己指定 this 關(guān)鍵字值的機(jī)會(huì),即每個(gè)函數(shù)都有的 call、apply 方法。例如:fn1.call(obj1,arg1,arg2,.)或者 fn1.apply(obj1,arg

38、Array),都是將 obj1 作為 this 關(guān)鍵字,調(diào)用執(zhí)行 fn1 函數(shù),后面的參數(shù)都作為函數(shù) fn1 的參數(shù)。如果 obj1 為 null 或 undefined,則 GlobalObject 將作為 this 關(guān)鍵字的值;如果 obj1 不是 Object 類型,則轉(zhuǎn)化為 Object 類型。它們之間的唯一區(qū)別在于,apply 允許以數(shù)組的方式提供各個(gè)參數(shù),而 call 方法必須一個(gè)一個(gè)參數(shù)的給。作用域分配與變量訪問(wèn)規(guī)則在 ECMAScript 中,函數(shù)也是對(duì)象。函數(shù)對(duì)象在變量實(shí)例化過(guò)程中會(huì)根據(jù)函數(shù)聲明來(lái)創(chuàng)建,或者是在計(jì)算函數(shù)表達(dá)式或調(diào)用 Function 構(gòu)造函數(shù)時(shí)創(chuàng)建。每個(gè)函數(shù)對(duì)

39、象都有一個(gè)內(nèi)部的scope屬性,這個(gè)屬性也由對(duì)象列表(鏈)組成。這個(gè)內(nèi)部的scope屬性引用的就是創(chuàng)建它們的執(zhí)行環(huán)境的作用域鏈,同時(shí),當(dāng)前執(zhí)行環(huán)境的活動(dòng)對(duì)象被添加到該對(duì)象列表的頂部。當(dāng)我們?cè)诤瘮?shù)內(nèi)部訪問(wèn)變量時(shí),其實(shí)就是在作用域鏈上尋找變量的過(guò)程。示例代碼:functionouter()vari=10;functioninner()varj=100;alert(j);/100alert(i);/10alert(adf);inner();outer();執(zhí)行過(guò)程如下:1 .載入代碼,創(chuàng)建全局執(zhí)行環(huán)境,在可變對(duì)象(window)中添加 outer 變量,其指向于函數(shù)對(duì)象 outer,此時(shí)作用域鏈中只

40、有 window 對(duì)象.2 .執(zhí)行代碼,當(dāng)程序執(zhí)行到 outer()時(shí),會(huì)在全局對(duì)象中尋找 outer 變量,成功調(diào)用。3 .創(chuàng)建 outer 的執(zhí)行環(huán)境,此時(shí)會(huì)新創(chuàng)建一個(gè)活動(dòng)對(duì)象,添加變量 i,設(shè)置值為 10,添加變量 inner,指向于函數(shù)對(duì)象 inner.并將活動(dòng)對(duì)象壓入作用域鏈中.并將函數(shù)對(duì)象 outer 的scope屬性指向活動(dòng)對(duì)象 outer。此時(shí)作用域鏈為 outer 的活動(dòng)對(duì)象+window.4 .執(zhí)行代碼,為 i 成功賦值。當(dāng)程序執(zhí)行到 inner()時(shí),會(huì)在函數(shù)對(duì)象 outer 的scope中尋找 inner 變量。找到后成功調(diào)用。5 .創(chuàng)建 inner 的執(zhí)行環(huán)境,新建一

41、個(gè)活動(dòng)對(duì)象,添加變量 j,賦值為 100,并將該活動(dòng)對(duì)象壓入作用域鏈中,并函數(shù)對(duì)象 inner 的scope屬性指向活動(dòng)對(duì)象 inner.此時(shí)作用域鏈為:inner 的活動(dòng)對(duì)象+outer 的活動(dòng)對(duì)象+window.6 .執(zhí)行代碼為 j 賦值,當(dāng)訪問(wèn) i、j 時(shí)成功在作用域中找到對(duì)應(yīng)的值并輸出,而當(dāng)訪問(wèn)變量 adf 時(shí),沒(méi)有在作用域中尋找到,訪問(wèn)出錯(cuò)棧堆員思再抵越朝LinksusMediaCummunicattunGroup閉包原理ECMAScript 允許使用內(nèi)部函數(shù)一一即函數(shù)定義和函數(shù)表達(dá)式位于另一個(gè)函數(shù)的函數(shù)體內(nèi)。而且,這些內(nèi)部函數(shù)可以訪問(wèn)它們所在的外部函數(shù)中聲明的所有局部變量、參數(shù)和聲

42、明的其他內(nèi)部函數(shù)。當(dāng)其中一個(gè)這樣的內(nèi)部函數(shù)在包含它們的外部函數(shù)之外被調(diào)用時(shí),就會(huì)形成閉包。也就是說(shuō),內(nèi)部函數(shù)會(huì)在外部函數(shù)返回后被執(zhí)行。而當(dāng)這個(gè)內(nèi)部函數(shù)執(zhí)行時(shí),它仍然必需訪問(wèn)其外部函數(shù)的局部變量、參數(shù)以及其他內(nèi)部函數(shù)。這些局部變量、參數(shù)和函數(shù)聲明(最初時(shí))的值是外部函數(shù)返回時(shí)的值,但也會(huì)受到內(nèi)部函數(shù)的影響。示例代碼:varincrement=(function()varid=0;returnfunction()return+id;)()alert(increment();/1alert(increment();/2上述代碼的解釋:在執(zhí)行第二個(gè) alert(increment()的語(yǔ)句時(shí),按理說(shuō)變

43、量 id 在執(zhí)行完第一個(gè) alert(increment()語(yǔ)句后就應(yīng)該銷毀了,但是由于在此函數(shù)外城函數(shù)的返回值是一個(gè)內(nèi)層函數(shù),而 JavaScript 使用自動(dòng)垃圾回收來(lái)釋放對(duì)象內(nèi)存,所以此時(shí)內(nèi)層函數(shù)并沒(méi)有銷魂,同時(shí)變量 id 得以保留,因此在第二次執(zhí)行 alert(increment()時(shí) id 的初始值是 1 而非 0函數(shù)形式參數(shù)與arguments實(shí)例代碼:bnksusfunctionsay(msg,other,garbage)alert(arguments1);/worldvarother=nicetomeetyou!;varmsg;alert(arguments.length);a

44、lert(msg);/helloalert(other);/nicetomeetyou!alert(arguments1);/nicetomeetyou!alert(garbage);/undefinedsay(hello,world);簡(jiǎn)單的內(nèi)存圖注:虛線表示的是曾經(jīng)引用的指向。Javascript 函數(shù)有形式參數(shù)和實(shí)際參數(shù)。形式參數(shù)是定義方法時(shí)所明確指定的參數(shù),由于 Javascript 語(yǔ)言的靈活性,javascript 不要求方法調(diào)用時(shí),所傳遞參數(shù)個(gè)數(shù)與形式參數(shù)一致.。javascript實(shí)際調(diào)用時(shí)所傳遞的參數(shù)就是實(shí)際參數(shù)。arguments 指的就是實(shí)際參數(shù)。從 say 方法中可以看

45、出, say定義了三個(gè)形式參數(shù), 而實(shí)際調(diào)用時(shí)只傳遞了兩個(gè)值。 因此 arguments.length的值為 2,而不是 3.接著我們來(lái)看一下 arguments的特殊行為,個(gè)人感覺(jué) arguments 會(huì)將所有的實(shí)際參數(shù)都當(dāng)作對(duì)象來(lái)看待,對(duì)于基本數(shù)據(jù)類型的實(shí)際參數(shù)則會(huì)轉(zhuǎn)換為其對(duì)應(yīng)的對(duì)象類型。這是根據(jù)在函數(shù)內(nèi)定義與形式參數(shù)同名的變量并賦值,arguments 對(duì)應(yīng)的值會(huì)跟著改變來(lái)判斷的。由于在實(shí)際調(diào)用的過(guò)程中實(shí)際參數(shù) other 被重新定義了,所以在 alert(other)語(yǔ)句執(zhí)行時(shí)返回的結(jié)果是 nicetomeetyou!而不是調(diào)用 say時(shí)傳遞的形式參數(shù) world,而兩次執(zhí)行 aler

46、t(arguments1)的結(jié)果不一樣是因?yàn)榈谝淮?arguments1指向 other,而 other 指向 world,第二次 arguments1同樣指向 other,但是此時(shí) other 已經(jīng)由原來(lái)指向 world 變?yōu)橹赶蛄?nicetomeetyou!總結(jié)執(zhí)行模型完整實(shí)例分析:varouterVar1=variableinglobalcode;functionfn1(arg1,arg2)varinnerVar1=variableinfunctioncode;functionfn2()returnouterVar1+-+innerVar1+-+-+(arg1+arg2);returnfn2();varouterVar2=fn1(10,20);執(zhí)行處理過(guò)程大致如下:1 .初始化 GlobalObject 即 window 對(duì)象,VariableObject 為 window 對(duì)象本身。創(chuàng)建 ScopeChain 對(duì)象,假設(shè)為 scope_1,其中只包含 window 對(duì)

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論