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

資訊專欄INFORMATION COLUMN

根治JavaScript中的this-ECMAScript規(guī)范解讀

notebin / 3292人閱讀

摘要:執(zhí)行函數(shù)調(diào)用規(guī)范中的第一步是一個(gè)明顯的賦值語(yǔ)句,我們查看規(guī)范,賦值語(yǔ)句會(huì)發(fā)生什么可以看出簡(jiǎn)單賦值語(yǔ)句返回的是對(duì)等于號(hào)右邊進(jìn)行之后的結(jié)果,上一節(jié)講了,執(zhí)行過(guò)就會(huì)返回的類型,此處會(huì)返回也就是一個(gè)類型。

前言

this是JavaScript中的著名月經(jīng)題,每隔一段時(shí)間就有人翻出了拿各種奇怪的問(wèn)題出來(lái)討論,每次都會(huì)引發(fā)一堆口水之爭(zhēng)。從搜索引擎搜了一下現(xiàn)在的比較熱門(mén)的關(guān)于this的用法,如:Javascript的this用法深入理解JavaScript中的this關(guān)鍵字你不知道的this 等文章幾乎都是從現(xiàn)象出發(fā),總結(jié)this在不同場(chǎng)景下的指向結(jié)果,如同江湖郎中一般,都沒(méi)有從根本上解釋現(xiàn)象出現(xiàn)的原因,這就導(dǎo)致每次有了關(guān)于this的題層出不窮,因?yàn)榻?jīng)驗(yàn)總結(jié)只是教會(huì)了你現(xiàn)有的場(chǎng)景,而沒(méi)有教會(huì)你如何解釋新的場(chǎng)景。

老司機(jī)都知道,發(fā)展到今天,有規(guī)范在,有源碼在,早已經(jīng)不是IE6時(shí)代,還需要總結(jié)使用經(jīng)驗(yàn)場(chǎng)景也太不科學(xué)了。最近又在網(wǎng)上刷到關(guān)于this的討論,正巧在規(guī)范中追尋過(guò)this的秘密,在這里分享一下個(gè)人經(jīng)驗(yàn)。
*以下規(guī)范均引用ES5

理論篇

規(guī)范中之處ECMAScript有三種可執(zhí)行代碼:

全局代碼(Global code

eval代碼(Eval code

函數(shù)代碼(Function code

其中,對(duì)于全局代碼直接指向global object,eval代碼由于已經(jīng)不推薦使用暫不做討論,我們主要關(guān)注函數(shù)代碼中的 this 如何指定。

進(jìn)入函數(shù)代碼

The following steps are performed when control enters the execution context for function code contained in function object F, a caller provided thisArg, and a caller provided argumentsList

規(guī)范指出,當(dāng)執(zhí)行流進(jìn)入函數(shù)代碼時(shí),由函數(shù)調(diào)用者提供 thisArgargumentsList。所以我們需要繼續(xù)尋找,查看函數(shù)調(diào)用時(shí)候this是如何傳遞進(jìn)去的。

函數(shù)調(diào)用

The production CallExpression : MemberExpression Arguments is evaluated as follows:
1.Let ref be the result of evaluating MemberExpression.
...
6.If Type(ref) is Reference, then
?a. If IsPropertyReference(ref) is true, then
??i. Let thisValue be GetBase(ref).
?b. Else, the base of ref is an Environment Record
??i. Let thisValue be the result of calling the ImplicitThisValue concrete method of GetBase(ref).
7.Else, Type(ref) is not Reference.
?a. Let thisValue be undefined.

從上述規(guī)范中,在函數(shù)調(diào)用發(fā)生時(shí),首先會(huì)對(duì)函數(shù)名部分進(jìn)行計(jì)算并賦值給 ref ,6、7中
幾個(gè)if else就決定了一個(gè)函數(shù)調(diào)用發(fā)生時(shí),this會(huì)指向何方。

在套用if else之前,我們還需要稍微了解一下 Type(ref) is Reference 中的 Reference是個(gè)什么東東。

Reference type

Reference type按字面翻譯就是引用類型,但是它并不是我們常說(shuō)的JavaScript中的引用類型,它是一個(gè)規(guī)范類型(實(shí)際并不存在),也就是說(shuō)是為了解釋規(guī)范某些行為而存在的,比如delete、typeof、賦值語(yǔ)句等。規(guī)范類型設(shè)計(jì)用于解析命名綁定的,它由三部分組成:

base value,指向引用的原值

referenced name,引用的名稱

strict reference flag,標(biāo)示是否嚴(yán)格模式

用大白話講,就是規(guī)范中定義了一種類型叫做Reference用來(lái)引用其他變量,它有一個(gè)規(guī)定的數(shù)據(jù)結(jié)構(gòu)。由于是規(guī)范類型,所以什么情況下會(huì)返回Reference規(guī)范上也會(huì)寫(xiě)得一清二楚。
至此,我們就可以直接開(kāi)始實(shí)戰(zhàn)了 ^ ^

實(shí)戰(zhàn)篇

我們通過(guò)上述理論來(lái)解釋下面代碼中的this:

foo();

foo.bar();

(f = foo.bar)();

如何解釋foo();

1 執(zhí)行函數(shù)調(diào)用規(guī)范中的第一步:

Let ref be the result of evaluating MemberExpression.

MemberExpression就是括號(hào)左邊的部分,此處很簡(jiǎn)單就是 foo。foo我們知道就是一個(gè)標(biāo)示符,那么執(zhí)行foo的時(shí)候會(huì)發(fā)生什么呢?答案都在規(guī)范中
11.1.2 Identifier Reference

An Identifier is evaluated by performing Identifier Resolution as specified in 10.3.1. The result of evaluating anIdentifier is always a value of type Reference.

標(biāo)示符被執(zhí)行的時(shí)候會(huì)進(jìn)行標(biāo)示符解析(Identifier Resolution),看10.3.1。(連章節(jié)都標(biāo)好了好伐,只需要點(diǎn)過(guò)去就行了。)

10.3.1 Identifier Resolution

1.Let env be the running execution context’s LexicalEnvironment.
...
3.Return the result of calling GetIdentifierReference function passing env, Identifier, and strict as arguments.

看這個(gè)返回,返回了 GetIdentifierReference 方法的結(jié)果,所以我們還需要再走一步(要有耐心 - -)

GetIdentifierReference

Return a value of type Reference whose base value is envRec, whose referenced name is name, and whose strict mode flag is strict.

我們看此處返回了一個(gè)Reference , base value 是 envRec 也就是 10.3.1中傳入的 execution context’s LexicalEnvironment
(詞法環(huán)境為環(huán)境記錄項(xiàng)Environment Record的組成,它是規(guī)范用來(lái)管理當(dāng)前作用域下面變量的類型,此處不用理解,知道它返回了這個(gè)東東就行了)
其抽象數(shù)據(jù)結(jié)構(gòu)大概為:

foo_reference = {
    "base": LexicalEnvironment,
    "name": "foo",
    "strict": false
}

至此,第一步執(zhí)行完畢,ref = foo_reference

2 因?yàn)槭莚eference, 執(zhí)行6:

Type(ref) is Reference

3 因?yàn)槭荅nvironment Record,執(zhí)行 6.b:

Else, the base of ref is an Environment Record
Let thisValue be the result of calling the ImplicitThisValue concrete method of GetBase(ref).

4 ImplicitThisValue
最后,thisValue等于執(zhí)行ImplicitThisValue的結(jié)果,還是查看規(guī)范:

10.2.1.1.6 ImplicitThisValue()

Declarative Environment Records always return undefined as their ImplicitThisValue.

到此我們知道,foo()執(zhí)行時(shí), thisValue = undefined; , 對(duì)應(yīng)到 JavaScript 代碼中的 this,還差最后一步:

Else if thisArg is null or undefined, set the ThisBinding to the global object.

真相大白:foo()執(zhí)行時(shí),this = global = window

如何解釋 foo.bar()

1 執(zhí)行函數(shù)調(diào)用規(guī)范中的第一步:

Let ref be the result of evaluating MemberExpression.

foo.bar我們都知道是一個(gè)屬性訪問(wèn),那么執(zhí)行屬性訪問(wèn)的時(shí)候會(huì)發(fā)生什么呢?答案都在規(guī)范中
11.2.1 Property Accessors

The production MemberExpression : MemberExpression [ Expression ] is evaluated as follows:
1.Let baseReference be the result of evaluating MemberExpression.
2.Let baseValue be GetValue(baseReference)
8.Return a value of type Reference whose base value is baseValue and whose referenced name ispropertyNameString, and whose strict mode flag is strict

baseReference 等于執(zhí)行 MemberExpression 在此處為 []左邊的語(yǔ)句即 foo 的結(jié)果,上一節(jié)已經(jīng)說(shuō)過(guò)了返回一個(gè) reference.

baseValue 等于 GetValue(baseReference) 。

[8.7.1 GetValue](http://es5.github.io/#x8.7.1)   
( GetValue屬于一個(gè)規(guī)范中比較重要的方法,此處為節(jié)約篇幅,暫時(shí)不講,以后可以單開(kāi)文章講解。暫時(shí)記住他的結(jié)果一般為:如果是reference傳入,會(huì)返回一個(gè)普通類型出來(lái)。比如 foo 為reference,通過(guò)GetValue之后就是一個(gè)普通的 object,也就是 foo 對(duì)應(yīng)的 js 類型本身。)

reference_foo_bar = {
    "base": foo,
    "name": "bar",
    "strict": false
}

2 因?yàn)槭莚eference, 執(zhí)行6:

Type(ref) is Reference

3 因?yàn)槭菍傩砸妙愋?執(zhí)行 6.a:

If IsPropertyReference(ref) is true, then
i.Let thisValue be GetBase(ref).

GetBase(ref) = reference_foo_bar.base = foo ;

真相大白, foo.bar() 執(zhí)行時(shí) this 指向 foo

如何解釋 (f = foo.bar)()

這個(gè)語(yǔ)句屬于罕見(jiàn)寫(xiě)法,在各種經(jīng)驗(yàn)總結(jié)中屬于高級(jí)技巧,但是通過(guò)規(guī)范,一樣分分鐘搞定。

1 執(zhí)行函數(shù)調(diào)用規(guī)范中的第一步:

Let ref be the result of evaluating MemberExpression.

f = foo.bar 是一個(gè)明顯的賦值語(yǔ)句,我們查看規(guī)范,賦值語(yǔ)句會(huì)發(fā)生什么:

[11.13.1 Simple Assignment ( = )] (http://es5.github.io/#x11.13.1)

The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows:

Let rref be the result of evaluating AssignmentExpression.

Let rval be GetValue(rref)

Return rval.

可以看出簡(jiǎn)單賦值語(yǔ)句返回的是對(duì)等于號(hào)右邊進(jìn)行GetValue之后的結(jié)果,上一節(jié)講了,執(zhí)行過(guò)GetValue就會(huì)返回js的類型,此處會(huì)返回 foo.bar 也就是一個(gè) [Object Function] 類型。

2 ref不是reference,執(zhí)行7

7.Else, Type(ref) is not Reference.

Let thisValue be undefined.

3 thisValue = undefined

同理:

Else if thisArg is null or undefined, set the ThisBinding to the global object.

真相大白, (f = foo.bar)() 執(zhí)行時(shí) this = global = window

老司機(jī)的經(jīng)驗(yàn)

雖然我們不是江湖郎中,但是每次查詢規(guī)范也有點(diǎn)麻煩,此處還是有一定規(guī)律可循的。
我們觀察上述過(guò)程,其實(shí)最關(guān)鍵的就是判斷返回值是不是 reference ,如果不是,直接可以推出等于window,如果是,只需要看是不是屬性 reference。這里有外國(guó)友人統(tǒng)計(jì)過(guò)一張速查表:

Example Reference? Notes
"foo" No
123 No
/x/ No
({}) No
(function(){}) No
foo Yes Could be unresolved reference if foo is not defined
foo.bar Yes Property reference
(123).toString Yes Property reference
(function(){}).toString Yes Property reference
(1,foo.bar) No Already evaluated, BUT see grouping operator exception
(f = foo.bar) No Already evaluated, BUT see grouping operator exception
(foo) Yes Grouping operator does not evaluate reference
(foo.bar) Yes Ditto with property reference
結(jié)語(yǔ)

只想說(shuō)一句:答案都在規(guī)范中,答案都在規(guī)范中答案都在規(guī)范中 。與其讀微博上某些不靠譜大V的總結(jié),不如去擼一遍規(guī)范。

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

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

相關(guān)文章

  • 正在失業(yè)中的《課多周刊》(第3期)

    摘要:正在失業(yè)中的課多周刊第期我們的微信公眾號(hào),更多精彩內(nèi)容皆在微信公眾號(hào),歡迎關(guān)注。若有幫助,請(qǐng)把課多周刊推薦給你的朋友,你的支持是我們最大的動(dòng)力。是一種禍害譯本文淺談了在中關(guān)于的不好之處。淺談超時(shí)一運(yùn)維的排查方式。 正在失業(yè)中的《課多周刊》(第3期) 我們的微信公眾號(hào):fed-talk,更多精彩內(nèi)容皆在微信公眾號(hào),歡迎關(guān)注。 若有幫助,請(qǐng)把 課多周刊 推薦給你的朋友,你的支持是我們最大的...

    robin 評(píng)論0 收藏0
  • 正在失業(yè)中的《課多周刊》(第3期)

    摘要:正在失業(yè)中的課多周刊第期我們的微信公眾號(hào),更多精彩內(nèi)容皆在微信公眾號(hào),歡迎關(guān)注。若有幫助,請(qǐng)把課多周刊推薦給你的朋友,你的支持是我們最大的動(dòng)力。是一種禍害譯本文淺談了在中關(guān)于的不好之處。淺談超時(shí)一運(yùn)維的排查方式。 正在失業(yè)中的《課多周刊》(第3期) 我們的微信公眾號(hào):fed-talk,更多精彩內(nèi)容皆在微信公眾號(hào),歡迎關(guān)注。 若有幫助,請(qǐng)把 課多周刊 推薦給你的朋友,你的支持是我們最大的...

    Joyven 評(píng)論0 收藏0
  • JavaScript深入之從ECMAScript規(guī)范解讀this

    摘要:深入系列第六篇,本篇我們追根溯源,從規(guī)范解讀在函數(shù)調(diào)用時(shí)到底是如何確定的。因?yàn)槲覀円獜囊?guī)范開(kāi)始講起。規(guī)范類型包括和。下一篇文章深入之執(zhí)行上下文深入系列深入系列目錄地址。如果有錯(cuò)誤或者不嚴(yán)謹(jǐn)?shù)牡胤?,?qǐng)務(wù)必給予指正,十分感謝。 JavaScript深入系列第六篇,本篇我們追根溯源,從 ECMAScript5 規(guī)范解讀 this 在函數(shù)調(diào)用時(shí)到底是如何確定的。 前言 在《JavaScript...

    TIGERB 評(píng)論0 收藏0
  • 由 ECMA 規(guī)范解讀 Javascript 可執(zhí)行上下文概念

    摘要:不包括作為其嵌套函數(shù)的被解析的源代碼。作用域鏈當(dāng)代碼在一個(gè)環(huán)境中執(zhí)行時(shí),會(huì)創(chuàng)建變量對(duì)象的一個(gè)作用域鏈。棧結(jié)構(gòu)最頂層的執(zhí)行環(huán)境稱為當(dāng)前運(yùn)行的執(zhí)行環(huán)境,最底層是全局執(zhí)行環(huán)境。無(wú)限制函數(shù)上下文?;蛘邟伋霎惓M顺鲆粋€(gè)執(zhí)行環(huán)境。 前言 其實(shí)規(guī)范這東西不是給人看的,它更多的是給語(yǔ)言實(shí)現(xiàn)者提供參考。但是當(dāng)碰到問(wèn)題找不到答案時(shí),規(guī)范往往能提供想要的答案 。偶爾讀一下能夠帶來(lái)很大的啟發(fā)和思考,如果只讀一...

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

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

0條評(píng)論

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