成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

ES規(guī)范解讀之賦值操作符&屬性訪問器

funnyZhang / 2907人閱讀

摘要:那么什么是基礎(chǔ)對(duì)象組件呢,舉兩個(gè)例子我們?cè)賮砜纯磳傩栽L問器,就是括號(hào)操作符及點(diǎn)號(hào)操作符都做了什么屬性訪問器也就是說括號(hào)跟點(diǎn)號(hào)對(duì)解釋器而言是一樣的。

ES規(guī)范解讀之賦值操作符&屬性訪問器

原文:https://github.com/kuitos/kuitos.github.io/issues/24
事情起源于某天某妹子同事在看angular文檔中關(guān)于Scope的說明Understanding Scopes(原文) 理解angular作用域(譯文)時(shí),對(duì)于文章中的例子有一點(diǎn)不理解,那個(gè)例子抽離細(xì)節(jié)之后大致是這樣的:

// 一個(gè)標(biāo)準(zhǔn)的構(gòu)造函數(shù)
function Scope(){}
Scope.prototype.array = [1,2,3];
Scope.prototype.string = "Scope";

// 生成Scope實(shí)例
var scopeInstance = new Scope();

當(dāng)我們?cè)L問scopeInstance上的屬性時(shí),假如scopeInstance上不存在該屬性,則js解釋器會(huì)從原型鏈上一層層往上找,直到找到有該屬性,否則返回undefined。

// get對(duì)象上某一屬性時(shí)會(huì)觸發(fā)原型鏈查找
console.log(scopeInstance.string); // "Scope"
console.log(scopeInstance.name); // undefined

而當(dāng)我們往scopeInstance上某一屬性設(shè)值時(shí),它并不會(huì)觸發(fā)原型鏈查找,而是直接給對(duì)象自身設(shè)值,如果對(duì)象上沒有該屬性則創(chuàng)建一個(gè)該屬性。

scopeInstance.string = "scopeInstance";
scopeInstance.array = [];
console.log(scopeInstance.string);    // "scopeInstance"
console.log(scopeInstance.array);    // []
console.log(Scope.prototype.string); // "Scope"
console.log(Scope.prototype.array); // [1,2,3]

總結(jié)起來,關(guān)于對(duì)象的屬性的set和get操作看上去有這樣一些特性:

讀(get)操作會(huì)觸發(fā)原型鏈查找,解釋器會(huì)從原型鏈一層層往上查找,直到找不到返回undefined.

寫(set)操作不會(huì)觸發(fā)原型鏈查找,寫操作會(huì)直接在對(duì)象上進(jìn)行,沒有這個(gè)屬性會(huì)新建一個(gè)屬性。

沒錯(cuò),這是最基本的原型鏈機(jī)制,我以前一直是這么理解的,然后我也是這么跟妹子解釋的,然而文章后面的例子打了我臉。。。例子大致是這樣的:

var scope2 = new Scope();
scope2.array[1] = 1;
console.log(scope2.array); // [1,1,3]
console.log(Scope.prototype.array); // [1,1,3]

WTF!!!
按照我的理解,寫操作跟原型鏈無關(guān),在對(duì)象自身操作。
順著這個(gè)思路,那么 scope2.array[1]=1這行代碼壓根就會(huì)報(bào)錯(cuò)啊,因?yàn)閟cope2在創(chuàng)建array屬性之前壓根就沒有自身的array屬性??!可是它竟然沒報(bào)錯(cuò)還把Scope.prototype給改了!
于是我又在想,是不是這種引用類型(array,object)都會(huì)觸發(fā)原型鏈查找,所以會(huì)出現(xiàn)這個(gè)結(jié)果?
然而我又想起前面那段代碼:

scopeInstance.array = [];
console.log(scopeInstance.array);    // []
console.log(Scope.prototype.array); // [1,2,3]

這下徹底斯巴達(dá)了?
從表象來看,scopeInstance.array[1]的讀寫操作都會(huì)觸發(fā)原型鏈查找,而為啥scopeInstance.array的寫操作就不會(huì)觸發(fā)。如果說引用類型都會(huì)觸發(fā),那么scopeInstace.array=[]就等價(jià)于Scope.prototype.array = [],但是事實(shí)并不是這樣。。。

碰到這種時(shí)候我只有祭出神器了(ecmascript),google什么的絕對(duì)不好使相信我。
翻到ecmascript關(guān)于賦值操作符那一小節(jié),es是這樣描述的

Simple Assignment (= )

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

Evaluate LeftHandSideExpression.

Evaluate AssignmentExpression.

Call GetValue(Result(2)).

Call PutValue(Result(1), Result(3)).

Return Result(3).

前面三步都知道,關(guān)鍵點(diǎn)在第四步, PutValue(Result(1), Result(3))
我們?cè)賮砜纯碢utValue干了啥

PutValue(V, W)

If Type(V) is not Reference, throw a ReferenceError exception.

Call GetBase(V).

If Result(2) is null, go to step 6.

Call the [[Put]] method of Result(2), passing GetPropertyName(V) for the property name and W for the value.

...

第二步有一個(gè)GetBase(V)操作,然后第四步依賴第二步的計(jì)算結(jié)果做最終賦值。
那么GetBase(V)究竟做了什么呢(V即我們賦值操作時(shí)候的左值)

GetBase(V)

GetBase(V). Returns the base object component of the reference V.

翻譯下來就是:返回引用V的基礎(chǔ)對(duì)象組件。
那么什么是基礎(chǔ)對(duì)象組件呢,舉兩個(gè)例子:

GetBase(this.array) => this
GetBase(this.info.name) => this.info
GetBase(this.array[1]) => this.array

我們?cè)賮砜纯磳傩栽L問器(Property Accessors),就是括號(hào)[]操作符及點(diǎn)號(hào).操作符都做了什么

屬性訪問器(Property Accessors)

MemberExpression . Identifier is identical in its behaviour to MemberExpression [ ]

也就是說括號(hào)跟點(diǎn)號(hào)對(duì)解釋器而言是一樣的。

The production MemberExpression : MemberExpression [ Expression ] is evaluated as follows:

Evaluate MemberExpression.

Call GetValue(Result(1)).
...

跟到GetValue

GetValue(V)

If Type(V) is not Reference, return V.

Call GetBase(V).

If Result(2) is null, throw a ReferenceError exception.

Call the [[Get]] method of Result(2), passing GetPropertyName( V) for the property name.

第四步的私有方法[[Get]]是關(guān)鍵:

[[Get]]

When the [[Get]] method of O is called with property name P, the following steps are taken:

If O doesn"t have a property with name P, go to step 4.

Get the value of the property.

Return Result(2).

If the [[Prototype]] of O is null, return undefined.

Call the [[Get]] method of [[Prototype]] with property name P.

Return Result(5).

意思很明顯,[[Get]]會(huì)觸發(fā)原型鏈查找.
我們?cè)倩氐劫x值操作符的PutValue操作,走到第四步

Call the [[Put]] method of Result(2), passing GetPropertyName(V) for the property name and W for the value.

這里的Result(2)就是GetBase(V)的結(jié)果,拿上面的例子也就是GetBase(this.array[2]) == this.array
再看看[[Put]]操作干了什么事情:

[[Put]]

When the [[Put]] method of O is called with property P and value V, the following steps are taken:

Call the [[CanPut]] method of O with name P.

If Result(1) is false, return.

If O doesn"t have a property with name P, go to step 6.

Set the value of the property to V. The attributes of the property are not changed.

Return.

Create a property with name P, set its value to V and give it empty attributes.

Return.

很簡(jiǎn)單,就是給對(duì)象o的屬性P賦值時(shí),o存在屬性P就直接覆蓋,沒有就新建屬性。此時(shí)無關(guān)原型鏈。

此時(shí)再結(jié)合我們自己的案例來看,scopeInstance.array[1]=2scopeInstance.array=[]究竟都干了啥(忽略不相關(guān)細(xì)節(jié)):

scopeInstance.array[1]=2

GetBase(scopeInstance.array[1]) == scopeInstance.array

GetValue(scopeInstance.array) => 觸發(fā)scopeInstace.array的[[Get]]方法,此時(shí)觸發(fā)原型鏈查找 => 找到 Scope.prototype.array

設(shè)值操作 Scope.prototype.array.[Put];

scopeInstance.array=[]

GetBase(scopeInstance.array) == scopeInstance

GetValue(scopeInstance) => scopeInstance object

設(shè)值操作 scopeInstance.[Put];

完美解釋所有現(xiàn)象!

如果思考的比較深入的同學(xué)可能會(huì)問,scopeInstance又從哪兒取來的呢?也是類似原型鏈這樣一層層往上查出來的么?這涉及到另一點(diǎn)知識(shí),js中的作用域,具體可以看我的另一篇文章一道js面試題引發(fā)的思考

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

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

相關(guān)文章

  • ES6 Iterator&Generator

    摘要:可迭代對(duì)象就具有屬性,它是一種與迭代器密切相關(guān)的對(duì)象。它通過指定的函數(shù)可以返回一個(gè)作用于附屬對(duì)象的迭代器。迭代器特點(diǎn)每次調(diào)用方法時(shí),返回一個(gè)數(shù)組,數(shù)組中兩個(gè)元素,分別表示鍵和值。示例之輸出輸出輸出之迭代器特點(diǎn)返回集合中存在的每一個(gè)鍵。 Iterator由來 不推薦Iterator方法。 Iterator 函數(shù)是一個(gè) SpiderMonkey 專有特性,并且會(huì)在某一時(shí)刻被刪除。有一點(diǎn),需...

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

    摘要:深入系列第六篇,本篇我們追根溯源,從規(guī)范解讀在函數(shù)調(diào)用時(shí)到底是如何確定的。因?yàn)槲覀円獜囊?guī)范開始講起。規(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
  • JavaScript & 6小時(shí)了解ES6基本語法

    摘要:返回布爾值,表示參數(shù)字符串是否在源字符串的頭部。參考語法返回一個(gè)布爾值與的全等操作符比較兼容環(huán)境把對(duì)象的值復(fù)制到另一個(gè)對(duì)象里淺拷貝定義方法用于將所有可枚舉的屬性的值從一個(gè)或多個(gè)源對(duì)象復(fù)制到目標(biāo)對(duì)象。語法要設(shè)置其原型的對(duì)象。 一步一步似爪牙。 前言 學(xué)習(xí)es6之前我們可能并不知道es6相比es5差距在哪, 但是這并不妨礙我們站在巨人的肩膀上; 程序員就是要樂于嘗鮮; 學(xué)習(xí)es6最終目的是...

    Amos 評(píng)論0 收藏0
  • ES規(guī)范解讀自增作符

    摘要:對(duì)于這種疑問,我們只能求助給出官方解釋后自增操作符從上的算法描述,我們能夠清晰的得知,后自增操作符是先自增賦值,然后返回自增前的值,這樣的一個(gè)順序。 ES規(guī)范解讀之自增操作符 原文:https://github.com/kuitos/kuitos.github.io/issues/24幾個(gè)月前,不知道什么緣由跟同事討論了起js里自增操作符(i++)的問題,現(xiàn)將前因后果整理出來,傳于世人...

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

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

0條評(píng)論

閱讀需要支付1元查看
<