對(duì)象內(nèi)部方法的算法

2018-06-16 15:08 更新

在以下算法說(shuō)明中假定 O 是一個(gè)原生 ECMAScript 對(duì)象,P 是一個(gè)字符串,Desc 是一個(gè)屬性說(shuō)明記錄,Throw 是一個(gè)布爾標(biāo)志。

[[GetOwnProperty]](P)

 當(dāng)用屬性名 P 調(diào)用 O 的 [[GetOwnProperty]] 內(nèi)部方法,采用以下步驟:

  1. 如果 O 不包含名為 P 的自身屬性,返回 undefined。
  2. 令 D 為無(wú)字段的新建屬性描述。
  3. 令 X 為 O 的名為 P 的自身屬性。
  4. 如果 X 是數(shù)據(jù)屬性,則設(shè)定 D.[[Value]] 為 X 的 [[Value]] 特性值。設(shè)定 D.[[Writable]] 為 X 的 [[Writable]] 特性值。
  5. 否則 X 是訪問(wèn)器屬性,所以設(shè)定 D.[[Get]] 為 X 的 [[Get]] 特性值。設(shè)定 D.[[Set]] 為 X 的 [[Set]] 特性值。
  6. 設(shè)定 D.[[Enumerable]] 為 X 的 [[Enumerable]] 特性值。
  7. 設(shè)定 D.[[Configurable]] 為 X 的 [[Configurable]] 特性值。
  8. 返回 D。

 然而,如果 O 是一個(gè)字符串對(duì)象,關(guān)于其 [[GetOwnProperty]] 的更多闡述定義在 15.5.5.2。

[[GetProperty]] (P)

 當(dāng)用屬性名 P 調(diào)用 O 的 [[GetProperty]] 內(nèi)部方法,采用以下步驟:

  1. 令 prop 為用屬性名 P 調(diào)用 O 的 [[GetOwnProperty]] 內(nèi)部方法的結(jié)果。
  2. 如果 prop 不是 undefined,返回 prop。
  3. 令 proto 為 O 的 [[Prototype]] 內(nèi)部屬性值。
  4. 如果 proto 是 null,返回 undefined。
  5. 用參數(shù) P 調(diào)用 proto 的 [[GetProperty]] 內(nèi)部方法,返回結(jié)果。

[[Get]] (P)

 當(dāng)用屬性名 P 調(diào)用 O 的 [[Get]] 內(nèi)部方法,采用以下步驟:

  1. 令 desc 為用屬性名 P 調(diào)用 O 的 [[GetProperty]] 內(nèi)部方法的結(jié)果。
  2. 如果 desc 是 undefined,返回 undefined。
  3. 如果 IsDataDescriptor(desc) 是 true,返回 desc.[[Value]]。
  4. 否則,IsAccessorDescriptor(desc) 必定是真,所以,令 getter 為 desc.[[Get]]。
  5. 如果 getter 是 undefined,返回 undefined。
  6. 用 O 作為 this,無(wú)參數(shù)調(diào)用 getter 的 [[Call]] 內(nèi)部方法,返回結(jié)果。

[[CanPut]] (P)

 當(dāng)用屬性名 P 調(diào)用 O 的 [[CanPut]] 內(nèi)部方法,采用以下步驟:

  1. 令 desc 為用參數(shù) P 調(diào)用 O 的 [[GetOwnProperty]] 內(nèi)部方法的結(jié)果。
  2. 如果 desc 不是 undefined,則如果 IsAccessorDescriptor(desc) 是 true,則如果 desc.[[Set]] 是 undefined,則返回 false。否則返回 true。否則,desc 必定是 DataDescriptor,所以返回 desc.[[Writable]] 的值。
  3. 令 proto 為 O 的 [[Prototype]] 內(nèi)部屬性。
  4. 如果 proto 是 null,則返回 O 的 [[Extensible]] 內(nèi)部屬性的值。
  5. 令 inherited 為用屬性名 P 調(diào)用 proto 的 [[GetProperty]] 內(nèi)部方法的結(jié)果。
  6. 如果 inherited 是 undefined,返回 O 的 [[Extensible]] 內(nèi)部屬性的值。
  7. 如果 IsAccessorDescriptor(inherited) 是 true,則如果 inherited.[[Set]] 是 undefined,則返回 false。否則返回 true。
  8. 否則,inherited 必定是 DataDescriptor如果 O 的 [[Extensible]] 內(nèi)部屬性是 false,返回 false。否則返回 inherited.[[Writable]] 的值。

 宿主對(duì)象可以定義受額外約束的 [[Put]] 操作。如果可能,宿主對(duì)象不應(yīng)該在 [[CanPut]] 返回 false 的情況下允許 [[Put]] 操作。

[[Put]] (P, V, Throw)

 當(dāng)用屬性名 P,值 V,布爾值 Throw 調(diào)用 O 的 [[Put]] 內(nèi)部方法,采用以下步驟:

  1. 如果用參數(shù) P 調(diào)用 O 的 [[CanPut]] 內(nèi)部方法的結(jié)果是 false,則如果 Throw 是 true,則拋出一個(gè) TypeError 異常。否則返回。
  2. 令 ownDesc 為用參數(shù) P 調(diào)用 O 的 [[GetOwnProperty]] 內(nèi)部方法的結(jié)果。
  3. 如果 IsDataDescriptor(ownDesc) 是 true,則令 valueDesc 為屬性描述 {[[Value]]: V}。用參數(shù) P,valueDesc,Throw 調(diào)用 O 的 [[DefineOwnProperty]] 內(nèi)部方法。返回。
  4. 令 desc 為用參數(shù) P 調(diào)用 O 的 [[GetProperty]] 內(nèi)部方法的結(jié)果。這可能是自身或繼承的訪問(wèn)器屬性描述或者是繼承的數(shù)據(jù)屬性描述。
  5. 如果 IsAccessorDescriptor(desc) 是 true,則令 setter 為不是 undefined 的 desc.[[Set]]。用 O 作為 this,V 作為唯一參數(shù)調(diào)用 setter 的 [[Call]] 內(nèi)部方法。
  6. 否則,按照以下步驟在對(duì)象 O 上創(chuàng)建名為 P 的命名數(shù)據(jù)屬性。令 newDesc 為屬性描述 {[[Value]]: V, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}。用參數(shù) P, newDesc, Throw 調(diào)用 O 的 [[DefineOwnProperty]] 內(nèi)部方法。
  7. 返回。

[[HasProperty]] (P)

 當(dāng)用屬性名 P 調(diào)用 O 的 [[HasProperty]] 內(nèi)部方法,采用以下步驟:

  1. 令 desc 為用屬性名 P 調(diào)用 O 的 [[GetProperty]] 內(nèi)部方法的結(jié)果。
  2. 如果 desc 是 undefined,則返回 false。
  3. 否則返回 true。

[[Delete]] (P, Throw)

 當(dāng)用屬性名 P 和布爾值 Throw 調(diào)用 O 的 [[Delete]] 內(nèi)部方法,采用以下步驟:

  1. 令 desc 為用屬性名 P 調(diào)用 O 的 [[GetOwnProperty]] 內(nèi)部方法的結(jié)果。
  2. 如果 desc 是 undefined,則返回 true。
  3. 如果 desc.[[Configurable]] 是 true,則在 O 上刪除名為 P 的自身屬性。返回 true。
  4. 否則如果 Throw,則拋出一個(gè) TypeError 異常。
  5. 返回 false。

[[DefaultValue]] (hint)

 當(dāng)用字符串 hint 調(diào)用 O 的 [[DefaultValue]] 內(nèi)部方法,采用以下步驟:

  1. 令 toString 為用參數(shù) "toString" 調(diào)用對(duì)象 O 的 [[Get]] 內(nèi)部方法的結(jié)果。
  2. 如果 IsCallable(toString) 是 true,則令 str 為用 O 作為 this 值,空參數(shù)列表調(diào)用 toString 的 [[Call]] 內(nèi)部方法的結(jié)果。如果 str 是原始值,返回 str。
  3. 令 valueOf 為用參數(shù) "valueOf" 調(diào)用對(duì)象 O 的 [[Get]] 內(nèi)部方法的結(jié)果。
  4. 如果 IsCallable(valueOf) 是 true,則令 val 為用 O 作為 this 值,空參數(shù)列表調(diào)用 valueOf 的 [[Call]] 內(nèi)部方法的結(jié)果。如果 val 是原始值,返回 val。
  5. 拋出一個(gè) TypeError 異常。

 當(dāng)用數(shù)字 hint 調(diào)用 O 的 [[DefaultValue]] 內(nèi)部方法,采用以下步驟:

  1. 令 valueOf 為用參數(shù) "valueOf" 調(diào)用對(duì)象 O 的 [[Get]] 內(nèi)部方法的結(jié)果。
  2. 如果 IsCallable(valueOf) 是 true,則令 val 為用 O 作為 this 值,空參數(shù)列表調(diào)用 valueOf 的 [[Call]] 內(nèi)部方法的結(jié)果。如果 val 是原始值,返回 val。
  3. 令 toString 為用參數(shù) "toString" 調(diào)用對(duì)象 O 的 [[Get]] 內(nèi)部方法的結(jié)果。
  4. 如果 IsCallable(toString) 是 true,則令 str 為用 O 作為 this 值,空參數(shù)列表調(diào)用 toString 的 [[Call]] 內(nèi)部方法的結(jié)果。如果 str 是原始值,返回 str。
  5. 拋出一個(gè) TypeError 異常。

 當(dāng)不用 hint 調(diào)用 O 的 [[DefaultValue]] 內(nèi)部方法時(shí),除非O 是 Date 對(duì)象的情況下把 hint 當(dāng)作字符串一樣解釋它的行為,除此之外把 hint 當(dāng)作數(shù)字一樣解釋它的行為。

 上面說(shuō)明的 [[DefaultValue]] 在原生對(duì)象中只能返回原始值。如果一個(gè)宿主對(duì)象實(shí)現(xiàn)了它自身的 [[DefaultValue]] 內(nèi)部方法,那么必須確保其 [[DefaultValue]] 內(nèi)部方法只能返回原始值。

[[DefineOwnProperty]] (P, Desc, Throw)

 在以下算法中,術(shù)語(yǔ)“拒絕”指代“如果 Throw 是 true,則拋出 TypeError 異常,否則返回 false。算法包含測(cè)試具體值的屬性描述 Desc 的各種字段的步驟。這種方式測(cè)試的字段事實(shí)上不需要真的在 Desc 里。如果一個(gè)字段不存在則將其值看作是 false。

 當(dāng)用屬性名 P,屬性描述 Desc,布爾值 Throw 調(diào)用 O 的 [[DefineOwnProperty]] 內(nèi)部方法,采用以下步驟:

  1. 令 current 為用屬性名 P 調(diào)用 O 的 [[GetOwnProperty]] 內(nèi)部屬性的結(jié)果。
  2. 令 extensible 為 O 的 [[Extensible]] 內(nèi)部屬性值。
  3. 如果 current 是 undefined 并且 extensible 是 false,則拒絕。
  4. 如果 current 是 undefined 并且 extensible 是 true,則如果 IsGenericDescriptor(Desc) 或 IsDataDescriptor(Desc) 是 true,則在 O 上創(chuàng)建名為 P 的自身數(shù)據(jù)屬性,Desc 描述了它的 [[Value]], [[Writable]], [[Enumerable]],[[Configurable]] 特性值。如果 Desc 的某特性字段值不存在,那么設(shè)定新建屬性的此特性為默認(rèn)值。否則,Desc 必定是訪問(wèn)器屬性描述,所以在 O 上創(chuàng)建名為 P 的自身訪問(wèn)器屬性,Desc 描述了它的 [[Get]], [[Set]], [[Enumerable]], [[Configurable]] 特性值。如果 Desc 的某特性字段值不存在,那么設(shè)定新建屬性的此特性為默認(rèn)值。
  5. 如果 Desc 不存在任何字段,返回 true。
  6. 如果 Desc 的任何字段都出現(xiàn)在 current 中,并且用 SameValue 算法比較 Desc 中每個(gè)字段值和 current 里對(duì)應(yīng)字段值,結(jié)果相同,則返回 true。
  7. 如果 current 的 [[Configurable]] 字段是 false,則如果 Desc 的 [[Configurable]] 字段是 true,則拒絕。如果 Desc 有 [[Enumerable]] 字段,并且 current 和 Desc 的 [[Enumerable]] 字段相互布爾否定,則拒絕。
  8. IsGenericDescriptor(Desc) 是 true,則不需要進(jìn)一步驗(yàn)證。
  9. 否則,如果 IsDataDescriptor(current) 和 IsDataDescriptor(Desc) 的結(jié)果不同,則如果 current 的 [[Configurable]] 字段是 false,則拒絕。如果 IsDataDescriptor(current) 是 true,則將對(duì)象 O 的名為 P 的數(shù)據(jù)屬性轉(zhuǎn)換為訪問(wèn)器屬性。保留轉(zhuǎn)換屬性的 [[Configurable]] 和 [[Enumerable]] 特性的現(xiàn)有值,并且設(shè)定屬性的其余特性為其默認(rèn)值。否則將對(duì)象 O 的名為 P 的訪問(wèn)器屬性轉(zhuǎn)換為數(shù)據(jù)屬性。保留轉(zhuǎn)換屬性的 [[Configurable]] 和 [[Enumerable]] 特性的現(xiàn)有值,并且設(shè)定屬性的其余特性為其默認(rèn)值。
  10. 否則,如果 IsDataDescriptor(current) 和 IsDataDescriptor(Desc) 都是 true,則如果 current 的 [[Configurable]] 字段是 false,則如果 current 的 [[Writable]] 字段是 false 并且 Desc 的 [[Writable]] 字段是 true,則拒絕。如果 current 的 [[Writable]] 字段是 false,則如果 Desc 有 [[Value]] 字段,并且 SameValue(Desc.[[Value]], current.[[Value]]) 是 false,則拒絕。否則,current 的 [[Configurable]] 字段是 true,所以可接受任何更改。
  11. 否則 IsAccessorDescriptor(current) 和 IsAccessorDescriptor(Desc) 都是 true,所以如果 current 的 [[Configurable]] 字段是 false,則如果 Desc 有 [[Set]] 字段,并且 SameValue(Desc.[[Set]], current.[[Set]]) 是 false,則拒絕。如果 Desc 有 [[Get]] 字段,并且 SameValue(Desc.[[Set]], current.[[Get]]) 是 false,則拒絕。
  12. Desc 擁有所有特性字段,設(shè)定對(duì)象 O 的名為 P 的屬性的對(duì)性特性為這些字段值。
  13. 返回 true。

 然而,如果 O 是一個(gè) Array 對(duì)象,其 [[DefineOwnProperty]] 內(nèi)部方法的更多闡述定義在 15.4.5.1

 如果 current 的 [[Configurable]] 字段是 true,那么步驟 10.b 允許 Desc 的任何字段與 current 對(duì)應(yīng)的字段不同。這甚至可以改變 [[Writable]] 特性為 false 的屬性的 [[Value]]。允許這種情況是因?yàn)橹凳?true 的 [[Configurable]] 特性會(huì)允許按照:首先設(shè)定 [[Writable]] 為 true,然后設(shè)定新 [[Value]],[[Writable]] 設(shè)為 false 的順序調(diào)用。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)