对象内部方法的算法

2018-06-16 15:08 更新

在以下算法说明中假定 O 是一个原生 ECMAScript 对象,P 是一个字符串,Desc 是一个属性说明记录,Throw 是一个布尔标志。

[[GetOwnProperty]](P)

 当用属性名 P 调用 O 的 [[GetOwnProperty]] 内部方法,采用以下步骤:

  1. 如果 O 不包含名为 P 的自身属性,返回 undefined。
  2. 令 D 为无字段的新建属性描述。
  3. 令 X 为 O 的名为 P 的自身属性。
  4. 如果 X 是数据属性,则设定 D.[[Value]] 为 X 的 [[Value]] 特性值。设定 D.[[Writable]] 为 X 的 [[Writable]] 特性值。
  5. 否则 X 是访问器属性,所以设定 D.[[Get]] 为 X 的 [[Get]] 特性值。设定 D.[[Set]] 为 X 的 [[Set]] 特性值。
  6. 设定 D.[[Enumerable]] 为 X 的 [[Enumerable]] 特性值。
  7. 设定 D.[[Configurable]] 为 X 的 [[Configurable]] 特性值。
  8. 返回 D。

 然而,如果 O 是一个字符串对象,关于其 [[GetOwnProperty]] 的更多阐述定义在 15.5.5.2。

[[GetProperty]] (P)

 当用属性名 P 调用 O 的 [[GetProperty]] 内部方法,采用以下步骤:

  1. 令 prop 为用属性名 P 调用 O 的 [[GetOwnProperty]] 内部方法的结果。
  2. 如果 prop 不是 undefined,返回 prop。
  3. 令 proto 为 O 的 [[Prototype]] 内部属性值。
  4. 如果 proto 是 null,返回 undefined。
  5. 用参数 P 调用 proto 的 [[GetProperty]] 内部方法,返回结果。

[[Get]] (P)

 当用属性名 P 调用 O 的 [[Get]] 内部方法,采用以下步骤:

  1. 令 desc 为用属性名 P 调用 O 的 [[GetProperty]] 内部方法的结果。
  2. 如果 desc 是 undefined,返回 undefined。
  3. 如果 IsDataDescriptor(desc) 是 true,返回 desc.[[Value]]。
  4. 否则,IsAccessorDescriptor(desc) 必定是真,所以,令 getter 为 desc.[[Get]]。
  5. 如果 getter 是 undefined,返回 undefined。
  6. 用 O 作为 this,无参数调用 getter 的 [[Call]] 内部方法,返回结果。

[[CanPut]] (P)

 当用属性名 P 调用 O 的 [[CanPut]] 内部方法,采用以下步骤:

  1. 令 desc 为用参数 P 调用 O 的 [[GetOwnProperty]] 内部方法的结果。
  2. 如果 desc 不是 undefined,则如果 IsAccessorDescriptor(desc) 是 true,则如果 desc.[[Set]] 是 undefined,则返回 false。否则返回 true。否则,desc 必定是 DataDescriptor,所以返回 desc.[[Writable]] 的值。
  3. 令 proto 为 O 的 [[Prototype]] 内部属性。
  4. 如果 proto 是 null,则返回 O 的 [[Extensible]] 内部属性的值。
  5. 令 inherited 为用属性名 P 调用 proto 的 [[GetProperty]] 内部方法的结果。
  6. 如果 inherited 是 undefined,返回 O 的 [[Extensible]] 内部属性的值。
  7. 如果 IsAccessorDescriptor(inherited) 是 true,则如果 inherited.[[Set]] 是 undefined,则返回 false。否则返回 true。
  8. 否则,inherited 必定是 DataDescriptor如果 O 的 [[Extensible]] 内部属性是 false,返回 false。否则返回 inherited.[[Writable]] 的值。

 宿主对象可以定义受额外约束的 [[Put]] 操作。如果可能,宿主对象不应该在 [[CanPut]] 返回 false 的情况下允许 [[Put]] 操作。

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

 当用属性名 P,值 V,布尔值 Throw 调用 O 的 [[Put]] 内部方法,采用以下步骤:

  1. 如果用参数 P 调用 O 的 [[CanPut]] 内部方法的结果是 false,则如果 Throw 是 true,则抛出一个 TypeError 异常。否则返回。
  2. 令 ownDesc 为用参数 P 调用 O 的 [[GetOwnProperty]] 内部方法的结果。
  3. 如果 IsDataDescriptor(ownDesc) 是 true,则令 valueDesc 为属性描述 {[[Value]]: V}。用参数 P,valueDesc,Throw 调用 O 的 [[DefineOwnProperty]] 内部方法。返回。
  4. 令 desc 为用参数 P 调用 O 的 [[GetProperty]] 内部方法的结果。这可能是自身或继承的访问器属性描述或者是继承的数据属性描述。
  5. 如果 IsAccessorDescriptor(desc) 是 true,则令 setter 为不是 undefined 的 desc.[[Set]]。用 O 作为 this,V 作为唯一参数调用 setter 的 [[Call]] 内部方法。
  6. 否则,按照以下步骤在对象 O 上创建名为 P 的命名数据属性。令 newDesc 为属性描述 {[[Value]]: V, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}。用参数 P, newDesc, Throw 调用 O 的 [[DefineOwnProperty]] 内部方法。
  7. 返回。

[[HasProperty]] (P)

 当用属性名 P 调用 O 的 [[HasProperty]] 内部方法,采用以下步骤:

  1. 令 desc 为用属性名 P 调用 O 的 [[GetProperty]] 内部方法的结果。
  2. 如果 desc 是 undefined,则返回 false。
  3. 否则返回 true。

[[Delete]] (P, Throw)

 当用属性名 P 和布尔值 Throw 调用 O 的 [[Delete]] 内部方法,采用以下步骤:

  1. 令 desc 为用属性名 P 调用 O 的 [[GetOwnProperty]] 内部方法的结果。
  2. 如果 desc 是 undefined,则返回 true。
  3. 如果 desc.[[Configurable]] 是 true,则在 O 上删除名为 P 的自身属性。返回 true。
  4. 否则如果 Throw,则抛出一个 TypeError 异常。
  5. 返回 false。

[[DefaultValue]] (hint)

 当用字符串 hint 调用 O 的 [[DefaultValue]] 内部方法,采用以下步骤:

  1. 令 toString 为用参数 "toString" 调用对象 O 的 [[Get]] 内部方法的结果。
  2. 如果 IsCallable(toString) 是 true,则令 str 为用 O 作为 this 值,空参数列表调用 toString 的 [[Call]] 内部方法的结果。如果 str 是原始值,返回 str。
  3. 令 valueOf 为用参数 "valueOf" 调用对象 O 的 [[Get]] 内部方法的结果。
  4. 如果 IsCallable(valueOf) 是 true,则令 val 为用 O 作为 this 值,空参数列表调用 valueOf 的 [[Call]] 内部方法的结果。如果 val 是原始值,返回 val。
  5. 抛出一个 TypeError 异常。

 当用数字 hint 调用 O 的 [[DefaultValue]] 内部方法,采用以下步骤:

  1. 令 valueOf 为用参数 "valueOf" 调用对象 O 的 [[Get]] 内部方法的结果。
  2. 如果 IsCallable(valueOf) 是 true,则令 val 为用 O 作为 this 值,空参数列表调用 valueOf 的 [[Call]] 内部方法的结果。如果 val 是原始值,返回 val。
  3. 令 toString 为用参数 "toString" 调用对象 O 的 [[Get]] 内部方法的结果。
  4. 如果 IsCallable(toString) 是 true,则令 str 为用 O 作为 this 值,空参数列表调用 toString 的 [[Call]] 内部方法的结果。如果 str 是原始值,返回 str。
  5. 抛出一个 TypeError 异常。

 当不用 hint 调用 O 的 [[DefaultValue]] 内部方法时,除非O 是 Date 对象的情况下把 hint 当作字符串一样解释它的行为,除此之外把 hint 当作数字一样解释它的行为。

 上面说明的 [[DefaultValue]] 在原生对象中只能返回原始值。如果一个宿主对象实现了它自身的 [[DefaultValue]] 内部方法,那么必须确保其 [[DefaultValue]] 内部方法只能返回原始值。

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

 在以下算法中,术语“拒绝”指代“如果 Throw 是 true,则抛出 TypeError 异常,否则返回 false。算法包含测试具体值的属性描述 Desc 的各种字段的步骤。这种方式测试的字段事实上不需要真的在 Desc 里。如果一个字段不存在则将其值看作是 false。

 当用属性名 P,属性描述 Desc,布尔值 Throw 调用 O 的 [[DefineOwnProperty]] 内部方法,采用以下步骤:

  1. 令 current 为用属性名 P 调用 O 的 [[GetOwnProperty]] 内部属性的结果。
  2. 令 extensible 为 O 的 [[Extensible]] 内部属性值。
  3. 如果 current 是 undefined 并且 extensible 是 false,则拒绝。
  4. 如果 current 是 undefined 并且 extensible 是 true,则如果 IsGenericDescriptor(Desc) 或 IsDataDescriptor(Desc) 是 true,则在 O 上创建名为 P 的自身数据属性,Desc 描述了它的 [[Value]], [[Writable]], [[Enumerable]],[[Configurable]] 特性值。如果 Desc 的某特性字段值不存在,那么设定新建属性的此特性为默认值。否则,Desc 必定是访问器属性描述,所以在 O 上创建名为 P 的自身访问器属性,Desc 描述了它的 [[Get]], [[Set]], [[Enumerable]], [[Configurable]] 特性值。如果 Desc 的某特性字段值不存在,那么设定新建属性的此特性为默认值。
  5. 如果 Desc 不存在任何字段,返回 true。
  6. 如果 Desc 的任何字段都出现在 current 中,并且用 SameValue 算法比较 Desc 中每个字段值和 current 里对应字段值,结果相同,则返回 true。
  7. 如果 current 的 [[Configurable]] 字段是 false,则如果 Desc 的 [[Configurable]] 字段是 true,则拒绝。如果 Desc 有 [[Enumerable]] 字段,并且 current 和 Desc 的 [[Enumerable]] 字段相互布尔否定,则拒绝。
  8. IsGenericDescriptor(Desc) 是 true,则不需要进一步验证。
  9. 否则,如果 IsDataDescriptor(current) 和 IsDataDescriptor(Desc) 的结果不同,则如果 current 的 [[Configurable]] 字段是 false,则拒绝。如果 IsDataDescriptor(current) 是 true,则将对象 O 的名为 P 的数据属性转换为访问器属性。保留转换属性的 [[Configurable]] 和 [[Enumerable]] 特性的现有值,并且设定属性的其余特性为其默认值。否则将对象 O 的名为 P 的访问器属性转换为数据属性。保留转换属性的 [[Configurable]] 和 [[Enumerable]] 特性的现有值,并且设定属性的其余特性为其默认值。
  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 拥有所有特性字段,设定对象 O 的名为 P 的属性的对性特性为这些字段值。
  13. 返回 true。

 然而,如果 O 是一个 Array 对象,其 [[DefineOwnProperty]] 内部方法的更多阐述定义在 15.4.5.1

 如果 current 的 [[Configurable]] 字段是 true,那么步骤 10.b 允许 Desc 的任何字段与 current 对应的字段不同。这甚至可以改变 [[Writable]] 特性为 false 的属性的 [[Value]]。允许这种情况是因为值是 true 的 [[Configurable]] 特性会允许按照:首先设定 [[Writable]] 为 true,然后设定新 [[Value]],[[Writable]] 设为 false 的顺序调用。


以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号