内部属性及方法

最新更新: 2019-08-23 15:08:40 阅读: 43次

本规范使用各种内部属性来定义对象值的语义。这些内部属性不是 ECMAScript 语言的一部分。本规范中纯粹是以说明为目的定义它们。ECMAScript 实现必须表现为仿佛它被这里描述的内部属性产生和操作。内部属性的名字用闭合双方括号 括起来。如果一个算法使用一个对象的一个内部属性,并且此对象没有实现需要的内部属性,那么抛出TypeError 异常。

 表 8 总结了本规范中适用于所有 ECMAScript 对象的内部属性。表 9 总结了本规范中适用于某些 ECMAScript 对象的内部属性。这些表中的描述如果没有特别指出是特定的原生 ECMAScript 对象,那么就说明了其在原生 ECMAScript 对象中的行为。宿主对象的内部属性可以支持任何依赖于实现的行为,只要其与本文档说的宿主对象的个别限制一直。

 下面表的“值的类域”一列定义了内部属性关联值的类型。类型名称参考第 8 章定义的类型,作为增强添加了一下名称:“any”指值可以是任何 ECMAScript 语言类型;“primitive”指 Undefined, Null, Boolean, String, , Number;“SpecOp”指内部属性是一个内部方法,一个抽象操作规范定义一个实现提供它的步骤。“SpecOp”后面跟着描述性参数名的列表。如果参数名和类型名一致那么这个名字用于描述参数的类型。如果“SpecOp”有返回值,那么这个参数列表后跟着“→”符号和返回值的类型。

所有对象共有的内部属性
内部属性 取值范围 说明
[[Prototype]] Object 或 Null 此对象的原型
[[Class]] String 说明规范定义的对象分类的一个字符串值
[[Extensible]] Boolean 如果是 true,可以向对象添加自身属性。
[[Get]] SpecOp(propertyName) → any 返回命名属性的值
[[GetOwnProperty]] SpecOp (propertyName) → Undefined 或 Property Descriptor 返回此对象的自身命名属性的属性描述,如果不存在返回 undefined
[[GetProperty]] SpecOp (propertyName) → Undefined 或 Property Descriptor 返回此对象的完全填入的自身命名属性的属性描述,如果不存在返回 undefined
[[Put]] SpecOp (propertyName, any, Boolean) 将指定命名属性设为第二个参数的值。flog 控制失败处理。
[[CanPut]] SpecOp (propertyName) → Boolean 返回一个 Boolean 值,说明是否可以在 PropertyName 上执行 [[Put]] 操作。
[[HasProperty]] SpecOp (propertyName) → Boolean 返回一个 Boolean 值,说明对象是否含有给定名称的属性。
[[Delete]] SpecOp (propertyName, Boolean) → Boolean 从对象上删除指定的自身命名属性。flog 控制失败处理。
[[DefaultValue]] SpecOp (Hint) → primitive Hint 是一个字符串。返回对象的默认值
[[DefineOwnProperty]] SpecOp (propertyName, PropertyDescriptor, Boolean) → Boolean 创建或修改自身命名属性为拥有属性描述里描述的状态。flog 控制失败处理。

 所有对象(包括宿主对象)必须实现表 8 中列出的所有内部属性。然而,对某些对象的 [[DefaultValue]] 内部方法,可以简单的抛出 TypeError 异常。

 所有对象都有一个叫做 [[Prototype]] 的内部属性。此对象的值是 null 或一个对象,并且它用于实现继承。一个原生属性是否可以把宿主对象作为它的 [[Prototype]] 取决于实现。所有 [[Prototype]] 链必须是有限长度(即,从任何对象开始,递归访问 [[Prototype]] 内部属性必须最终到头,并且值是 null)。从 [[Prototype]] 对象继承来的命名数据属性(作为子对象的属性可见)是为了 get 请求,但无法用于 put 请求。命名访问器属性会把 get 和 put 请求都继承。

 所有 ECMASCript 对象都有一个 Boolean 值的 [[Extensible]] 内部属性,它控制是否可以给对象添加命名属性。如果 [[Extensible]] 内部属性的值是 false 那么不得给对象添加命名属性。此外,如果 [[Extensible]] 是 false 那么不得更改对象的 [[Class]] 和 [[Prototype]] 内部属性的值。一旦 [[Extensible]] 内部属性的值设为 false 之后无法再更改为 true。

 本规范的定义中没有 ECMAScript 语言运算符或内置函数允许一个程序更改对象的 [[Class]] 或 [[Prototype]] 内部属性或把 [[Extensible]] 的值从 false 更改成 true。实现中修改 [[Class]], [[Prototype]], [[Extensible]] 的个别扩展必须不违反前一段定义的不变量。

 本规范的每种内置对象都定义了 [[Class]] 内部属性的值。宿主对象的 [[Class]] 内部属性的值可以是除了 "Arguments", "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math", "Number", "Object", "RegExp", "String" 的任何字符串。[[Class]] 内部属性的值用于内部区分对象的种类。注,本规范中除了通过 Object.prototype.toString ( 见 15.2.4.2) 没有提供任何手段使程序访问此值。

 除非特别指出,原生 ECMAScrpit 对象的公共内部方法的行为描述在 8.12。Array 对象的 [[DefineOwnProperty]] 内部方法有稍不同的实现,又有 String 对象的 [[GetOwnProperty]] 内部方法有稍不同的实现(见 15.5.5.2)。Arguments 对象(10.6)的 [[Get]],[[GetOwnProperty]],[[DefineOwnProperty]],[[Delete]] 有不同的实现。Function 对象(15.3)的 [[Get]] 的有不同的实现。

 除非特别指出,宿主对象可以以任何方式实现这些内部方法,一种可能是一个特别的宿主对象的 [[Get]] 和 [[Put]] 确实可以存取属性值,但 [[HasProperty]] 总是产生 false。然而,如果任何对宿主对象内部属性的操作不被实现支持,那么当试图操作时必须抛出 TypeError 异常。

 宿主对象的 [[GetOwnProperty]] 内部方法必须符合宿主对象每个属性的以下不变量 :

  • 如果属性是描述过的数据属性,并随着时间的推移,它可能返回不同的值,那么即使没有暴露提供更改值机制的其他内部方法,[[Writable]] 和 [[Configurable]] 之一或全部必须是 true。
  • 如果属性是描述过的数据属性,并且其 [[Writable]] 和 [[Configurable]] 都是 false。那么所有对 [[GetOwnProperty]] 的呼出,必须返回作为属性 [[Value]] 特性的SameValue(9.12)。
  • 如果 [[Writable]] 特性可以从 false 更改为 true,那么 [[Configurable]] 特性必须是 true。
  • 当 ECMAScript 代码监测到宿主对象的 [[Extensible]] 内部属性值是 false。那么如果调用 [[GetOwnProperty]] 描述一个属性是不存在,那么接下来所有调用这个属性必须也描述为不存在。

 如果 ECMAScript 代码监测到宿主对象的 [[Extensible]] 内部属性是 false,那么这个宿主对象的 [[DefineOwnProperty]] 内部方法不允许向宿主对象添加新属性。

 如果 ECMAScript 代码监测到宿主对象的 [[Extensible]] 内部属性是 false,那么它以后必须不能再改为 true。

只在某些对象中定义的内部属性Object
内部属性 取值范围 说明
[[PrimitiveValue]] primitive 与此对象的内部状态信息关联。对于标准内置对象只能用 Boolean, Date, Number, String 对象实现 [[PrimitiveValue]]。
[[Construct]] SpecOp(a List of any) → Object 通过 new 运算符调,创建对象。SpecOp 的参数是通过 new 运算符传的参数。实现了这个内部方法的对象叫做 构造器 。
[[Call]] SpecOp(any, a List of any) → any or Reference 运行与此对象关联的代码。通过函数调用表达式调用。SpecOp 的参数是一个 this 对象和函数调用表达式传来的参数组成的列表。实现了这个内部方法的对象是 可调用 的。只有作为宿主对象的可调用对象才可能返回 引用 值。
[[HasInstance]] SpecOp(any) → Boolean 返回一个表示参数对象是否可能是由本对象构建的布尔值。在标准内置 ECMAScript 对象中只有 Function 对象实现 [[HasInstance]]。
[[Scope]] Lexical Environment 一个定义了函数对象执行的环境的词法环境。在标准内置 ECMAScript 对象中只有 Function 对象实现 [[Scope]]。
[[FormalParameters]] List of Strings 一个包含 Function 的 FormalParameterList 的标识符字符串的可能是空的列表。在标准内置 ECMAScript 对象中只有 Function 对象实现 [[FormalParameterList]]。
[[Code]] ECMAScript code 函数的 ECMAScript 代码。在标准内置 ECMAScript 对象中只有 Function 对象实现 [[Code]]。
[[TargetFunction]] Object 使用标准内置的 Function.prototype.bind 方法创建的函数对象的目标函数。只有使用 Function.prototype.bind 创建的 ECMAScript 对象才有 [[TargetFunction]] 内部属性。
[[BoundThis]] any 使用标准内置的 Function.prototype.bind 方法创建的函数对象的预绑定的 this 值。只有使用 Function.prototype.bind 创建的 ECMAScript 对象才有 [[BoundThis]] 内部属性。
[[BoundArguments]] List of any 使用标准内置的 Function.prototype.bind 方法创建的函数对象的预绑定的参数值。只有使用 Function.prototype.bind 创建的 ECMAScript 对象才有 [[BoundArguments]] 内部属性。
[[Match]] SpecOp(String, index) → MatchResult 测试正则匹配并返回一个 MatchResult 值(见 15.10.2.1)。在标准内置 ECMAScript 对象中只有 RegExp 对象实现 [[Match]]。
[[ParameterMap]] 提供参数对象的属性和函数关联的形式参数之间的映射。只有参数对象才有 [[ParameterMap]] 内部属性。

1、引用规范类型

 引用类型用来说明 delete,typeof,赋值运算符这些运算符的行为。例如,在赋值运算中左边的操作数期望产生一个引用。通过赋值运算符左侧运算子的语法案例分析可以但不能完全解释赋值行为,还有个难点:函数调用允许返回引用。承认这种可能性纯粹是为了宿主对象。本规范没有定义返回引用的内置 ECMAScript 函数,并且也不提供返回引用的用户定义函数。(另一个不使用语法案列分析的原因是,那样将会影响规范的很多地方,冗长并且别扭。)

 一个 引用 (Reference) 是个已解决的命名绑定。一个引用由三部分组成, 基 (base) 值, 引用名称(referenced name) 和布尔值 严格引用 (strict reference) 标志。基值是 undefined, 一个 Object, 一个 Boolean, 一个 String, 一个 Number, 一个 environment record 中的任意一个。基值是 undefined 表示此引用可以不解决一个绑定。引用名称是一个字符串。

 本规范中使用以下抽象操作接近引用的组件:

  • GetBase(V)。 返回引用值 V 的基值组件。
  • GetReferencedName(V)。 返回引用值 V 的引用名称组件。
  • IsStrictReference(V)。 返回引用值 V 的严格引用组件。
  • HasPrimitiveBase(V)。 如果基值是 Boolean, String, Number,那么返回 true。
  • IsPropertyReference(V)。 如果基值是个对象或 HasPrimitiveBase(V) 是 true,那么返回 true;否则返回 false。
  • IsUnresolvableReference(V)。 如果基值是 undefined 那么返回 true,否则返回 false。

 本规范使用以下抽象操作来操作引用:

2、GetValue(v)

  1. 如果 Type(V) 不是引用 , 返回 V。
  2. 令 base 为调用 GetBase(V) 的返回值。
  3. 如果 IsUnresolvableReference(V), 抛出一个 ReferenceError 异常。
  4. 如果 IsPropertyReference(V), 那么
    1. 如果 HasPrimitiveBase(V) 是 false, 那么令 get 为 base 的 [[Get]] 内部方法 , 否则令 get 为下面定义的特殊的 [[Get]] 内部方法。
    2. 将 base 作为 this 值,传递 GetReferencedName(V) 为参数,调用 get 内部方法,返回结果。
  5. 否则 , base 必须是一个 environment record。
  6. 传递 GetReferencedName(V) 和 IsStrictReference(V) 为参数调用 base 的 GetBindingValue( 见 10.2.1) 具体方法,返回结果。

 GetValue 中的 V 是原始基值的 属性引用 时使用下面的 [[Get]] 内部方法。它用 base 作为他的 this 值,其中属性 P 是它的参数。采用以下步骤:

  1. 令 O 为 ToObject(base)。
  2. 令 desc 为用属性名 P 调用 O 的 [[GetProperty]] 内部方法的返回值。
  3. 如果 desc 是 undefined,返回 undefined。
  4. 如果 IsDataDescriptor(desc) 是 true,返回 desc.[[Value]]。
  5. 否则 IsAccessorDescriptor(desc) 必须是 true,令 getter 为 desc.[[Get]]。
  6. 如果 getter 是 undefined,返回 undefined。
  7. 提供 base 作为 this 值,无参数形式调用 getter 的 [[Call]] 内部方法,返回结果。

 上述方法之外无法访问在第一步创建的对象。实现可以选择不真的创建这个对象。使用这个内部方法给实际属性访问产生可见影响的情况只有在调用访问器函数时。

3、PutValue(v,w)

  1. 如果 Type(V) 不是引用,抛出一个 ReferenceError 异常。
  2. 令 base 为调用 GetBase(V) 的结果。
  3. 如果 IsUnresolvableReference(V),那么
    1. 如果 IsStrictReference(V) 是 true,那么
      1. 抛出 ReferenceError 异常。
    2. 用 GetReferencedName(V),W,false 作为参数调用全局对象的 [[Put]] 内部方法。
  4. 否则如果 IsPropertyReference(V),那么
    1. 如果 HasPrimitiveBase(V) 是 false,那么令 put 为 base 的 [[Put]] 内部方法,否则令 put 为下面定义的特殊的 [[Put]] 内部方法。
    2. 用 base 作为 this 值,用 GetReferencedName(V),W,IsStrictReference(V) 作为参数调用 put 内部方法。
  5. 否则 base 必定是 environment record 作为 base 的引用。所以,
    1. 用 GetReferencedName(V), W, IsStrictReference(V) 作为参数调用 base 的 SetMutableBinding (10.2.1) 具体方法。
  6. 返回。

 PutValue 中的 V 是原始基值的属性引用时使用下面的 [[Put]] 内部方法。用 base 作为 this 值,用属性 P,值 W,布尔标志 Throw 作为参数调用它。采用以下步骤:

  1. 令 O 为 ToObject(base)。
  2. 如果用 P 作为参数调用 O 的 [[CanPut]] 内部方法的结果是 false,那么
    1. 如果 Throw 是 true,那么抛出一个 TypeError 异常。
    2. 否则返回。
  3. 令 ownDesc 为用 P 作为参数调用 O 的 [[GetOwnProperty]] 内部方法的结果。
  4. 如果 IsDataDescriptor(ownDesc) 是 true,那么
    1. 如果 Throw 是 true,那么抛出一个 TypeError 异常。
    2. 否则返回。
  5. 令 desc 为用 P 作为参数调用 O 的 [[GetProperty]] 内部方法的结果。这可能是一个自身或继承的访问器属性描述或是一个继承的数据属性描述。
  6. 如果 IsAccessorDescriptor(desc) 是 true,那么
    1. 令 setter 为 desc.Set,他不能是 undefined。
    2. 用 base 作为 this 值,用只由 W 组成的列表作为参数调用 setter 的 [[Call]] 内部方法。
  7. 否则,这是要在临时对象 O 上创建自身属性的请求。
    1. 如果 Throw 是 true,抛出一个 TypeErroe 异常。
  8. 返回。

 上述方法之外无法访问在第一步创建的对象。实现可以选择不真的创建这个临时对象。使用这个内部方法给实际属性访问产生可见影响的情况只有在调用访问器函数时,或 Throw 未通过提前错误检查。当 Throw 是 true,试图在这个临时对象上创建新属性的任何属性分配操作会抛出一个错误。