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

資訊專欄INFORMATION COLUMN

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

funnyZhang / 2847人閱讀

摘要:那么什么是基礎對象組件呢,舉兩個例子我們再來看看屬性訪問器,就是括號操作符及點號操作符都做了什么屬性訪問器也就是說括號跟點號對解釋器而言是一樣的。

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

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

// 一個標準的構造函數
function Scope(){}
Scope.prototype.array = [1,2,3];
Scope.prototype.string = "Scope";

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

當我們訪問scopeInstance上的屬性時,假如scopeInstance上不存在該屬性,則js解釋器會從原型鏈上一層層往上找,直到找到有該屬性,否則返回undefined。

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

而當我們往scopeInstance上某一屬性設值時,它并不會觸發原型鏈查找,而是直接給對象自身設值,如果對象上沒有該屬性則創建一個該屬性。

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]

總結起來,關于對象的屬性的set和get操作看上去有這樣一些特性:

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

寫(set)操作不會觸發原型鏈查找,寫操作會直接在對象上進行,沒有這個屬性會新建一個屬性。

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

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

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

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

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

碰到這種時候我只有祭出神器了(ecmascript),google什么的絕對不好使相信我。
翻到ecmascript關于賦值操作符那一小節,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).

前面三步都知道,關鍵點在第四步, PutValue(Result(1), Result(3))
我們再來看看PutValue干了啥

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.

...

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

GetBase(V)

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

翻譯下來就是:返回引用V的基礎對象組件。
那么什么是基礎對象組件呢,舉兩個例子:

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

我們再來看看屬性訪問器(Property Accessors),就是括號[]操作符及點號.操作符都做了什么

屬性訪問器(Property Accessors)

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

也就是說括號跟點號對解釋器而言是一樣的。

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]]是關鍵:

[[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]]會觸發原型鏈查找.
我們再回到賦值操作符的PutValue操作,走到第四步

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

這里的Result(2)就是GetBase(V)的結果,拿上面的例子也就是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.

很簡單,就是給對象o的屬性P賦值時,o存在屬性P就直接覆蓋,沒有就新建屬性。此時無關原型鏈。

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

scopeInstance.array[1]=2

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

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

設值操作 Scope.prototype.array.[Put];

scopeInstance.array=[]

GetBase(scopeInstance.array) == scopeInstance

GetValue(scopeInstance) => scopeInstance object

設值操作 scopeInstance.[Put];

完美解釋所有現象!

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

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/86004.html

相關文章

  • ES6 Iterator&Generator

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

    xietao3 評論0 收藏0
  • JavaScript深入從ECMAScript規范解讀this

    摘要:深入系列第六篇,本篇我們追根溯源,從規范解讀在函數調用時到底是如何確定的。因為我們要從規范開始講起。規范類型包括和。下一篇文章深入之執行上下文深入系列深入系列目錄地址。如果有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝。 JavaScript深入系列第六篇,本篇我們追根溯源,從 ECMAScript5 規范解讀 this 在函數調用時到底是如何確定的。 前言 在《JavaScript...

    TIGERB 評論0 收藏0
  • JavaScript & 6小時了解ES6基本語法

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

    Amos 評論0 收藏0
  • ES規范解讀自增作符

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

    junnplus 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<