Object Type

对象类型的每个实例,也简称为对象,代表属性的集合。 对象中的每个属性要么是data property数据属性,要么是accessor property访问器属性:

  • data property: 将键值与ECMAScript语言值和一组布尔属性相关联。
  • accessor property:将一个键值与一个或两个访问器函数以及一组布尔属性相关联。 访问器函数用于存储或检索与属性关联的ECMAScript语言值。

对象的属性使用属性键进行唯一标识。property keys属性键要么是字符串(String),要么是符号(Symbol)。 所有字符串和符号,包括空字符串,都作为属性键有效。属性名称是字符串的属性键。

Data Property

数据属性是将键值与ECMAScript语言值和一组布尔属性相关联,具体有以下特性:

  • value:通过属性的get访问,可以是任何ECMAScript语言值, 默认为undefined
  • writable:boolean值,表示属性值是否可写,默认false
  • enumerable: boolean值,表示属性是否可枚举,使用for...in语句, 默认false
  • configurable:boolean值,表示属性是否可配置,表示属性是否可以删除,可以更改访问器属性,是否可以更改其特性, 默认false

Accessor Property

访问器属性是将一个键值与一个或两个访问器函数以及一组布尔属性相关联。 访问器函数用于存储或检索与属性关联的ECMAScript语言值,具体有以下特性:

  • get:访问器函数,用于检索属性值,执行值的get访问时,使用一个空的参数列表表示调用函数获取属性值。
  • set:访问器函数,用于存储属性值, 执行值的set访问时,使用一个单个参数列表表示调用函数设置属性值。
  • enumerable: boolean值,表示属性是否可枚举,使用for...in语句。
  • configurable:boolean值,表示属性是否可配置,表示属性是否可以删除,可以更改访问器属性为数据属性或者数据属性为访问器属性,是否可以更改其特性。

Internal Methods And Internal Slots

Note

在ECMAScript中,对象的实际语义是通过称为Internal Methods内部方法的算法指定的。 在ECMAScript引擎中的每个对象都与一组定义其运行时行为的内部方法相关联。 这些内部方法不是ECMAScript语言的一部分(纯粹是为了说明的目的)。 然而,ECMAScript实现中的每个对象都必须按照与其相关联的内部方法指定的方式运行

内部方法名是多态的。 这意味着当对不同的对象值调用公共的内部方法名时,它们可以执行不同的算法。 调用内部方法的实际对象是调用的“目标”。如果在运行时,算法的实现试图使用对象不支持的对象的内部方法,则会引发TypeError异常。

Internal Slots内部槽对应于与对象相关联并由各种ECMAScript规范算法使用的内部状态。 内部插槽不是对象属性,也不是继承的。

根据特定的内部插槽规范,这种状态可以由任何ECMAScript语言类型的值或特定的ECMAScript规范类型值组成。 除非另有明确规定,否则内部插槽是作为创建对象过程的一部分分配的,并且不能动态地添加到对象中。除非另有说明,否则内部插槽的初始值是未定义的值。

ECMAScript规范中的各种算法创建具有内部槽的对象。 然而,ECMAScript语言没有提供将内部插槽与对象相关联的直接方法。

内部方法和内部插槽在本规范中使用用双方括号[[]]括起来的名称来标识。

所有对象都有一个名为[[PrivateElements]]的内部槽,它是PrivateElements的列表。 此列表表示对象的私有字段、方法和访问器的值,默认是一个空列表。

ordinary object是一个对象,包含了以下标准:

  • 具有表1列出的内部方法
  • 具有[[Call]]内部方法
  • 具有[[Construct]]内部方法

exotic object也是一个对象,但不是一个普通对象。

表1总结了规范使用的基本内部方法,这些方法适用于ECMAScript代码创建或操作的所有对象。 每个对象都必须有所有基本内部方法的算法。然而,所有对象不一定对这些方法使用相同的算法。

表1

Internal MethodSignatureDescription
[[GetPrototypeOf]]() => Object | null确定为该对象提供继承属性的对象。空值表示没有继承的属性。
[[SetPrototypeOf]](Object | null ) => Boolean将此对象与提供继承属性的另一个对象相关联。传递null表示没有继承的属性。返回true表示操作成功完成,或返回false表示操作不成功。
[[IsExtensible]]() => Boolean确定是否允许向此对象添加其他属性。
[[preventExtensible]]() => Boolean控制是否可以向此对象添加新属性。如果操作成功,则返回true;如果操作不成功,则返回false。
[[GetOwnProperty]](propertyKey) => Undefined | Property Descriptor返回键为propertyKey的此对象的自有属性的属性描述符,如果不存在此类属性,则返回undefined。
[[DefineOwnProperty]](propertyKey, PropertyDescriptor) => Boolean 创建或更改其键为propertyKey的自有属性,使其状态由PropertyDescriptor描述。如果成功创建/更新该属性,则返回true;如果无法创建或更新该属性,则返回false。
[[HasProperty]](propertyKey) => Boolean返回一个布尔值,指示此对象是否已经拥有密钥为propertyKey的自有或继承属性。
[[Get]](propertyKey, Receiver) => any从该对象返回键为propertyKey的属性的值。如果必须执行任何ECMAScript代码来检索属性值,则在评估代码时将Receiver用作this值。
[[Set]](propertyKey, value, Receiver) => Boolean将键为propertyKey的属性的值设置为value。如果必须执行任何ECMAScript代码来设置属性值,则在评估代码时将Receiver用作this值。如果属性值已设置,则返回true;如果无法设置,则返回false。
[[Delete]](propertyKey) => Boolean从此对象中删除键为propertyKey的own属性。如果属性未被删除并且仍然存在,则返回false。如果属性已被删除或不存在,则返回true。
[[OwnPropertyKeys]]() => List of property keys返回一个列表,其元素都是对象自己的属性键。

表2额外的总结了函数对象的内部方法

表2

Internal MethodSignatureDescription
[[Call]](any, a List of any) => any执行与此对象关联的代码。通过函数调用表达式调用。内部方法的参数是this值和一个列表,其元素是调用表达式传递给函数的参数。实现此内部方法的对象是可调用的。
[[Construct]](a List of any, Object) => Object创建一个对象。通过new运算符或super调用触发。内部方法的第一参数是一个列表,其元素是构造函数调用或super调用的参数。第二个参数是new运算符最初应用的对象。实现此内部方法的对象称为构造函数。函数对象不一定是构造函数,此类非构造函数对象不一定有[[Construct]]内部方法。

Invariants of Essential Internal Methods

Note

ECMAScript引擎对象的内部方法必须符合不变量列表(也就是定义的行为和实际的行为要保持一致)。 普通ECMAScript对象以及规范中的所有标准外来对象都保持这些不变量。

ECMAScript代理对象通过运行时检查在[[ProxyHandler]]对象上调用的陷阱的结果来维护这些不变量。 任何提供外来对象的实现也必须为这些对象维护这些不变量。 违反这些不变量可能会导致ECMAScript代码具有不可预测的行为并产生安全问题。然而,违反这些不变量绝不能损害实现的内存安全。

不变性是指在所有情况下都必须满足的规则或约束条件。它们保证了对象行为的逻辑一致性,不会因某些内部方法的自定义实现而破坏语言的核心特性。

以内部方法[[GetOwnProperty]]实现中的不变性为例:

let obj = { name: "Alice" };
// 规范行为:如果 `name` 属性存在,其描述符必须与实际行为一致
console.log(Object.getOwnPropertyDescriptor(obj, "name"));
// { value: "Alice", writable: true, enumerable: true, configurable: true }

如果[[GetOwnProperty]]返回属性描述符value: 10,跟实际行为不一致,违反了不变性原则。

表1中其他内部方法也是一致的。

Ordinary and Exotic Objects Behaviours

Ordinary Internal Methods and Internal Slots

普通对象的内部槽如下表

Internal SlotsDescription
[[Prototype]]值要么是null,要么是一个对象,用于实现继承
[[Extensible]]用于实现对象中可扩展内部方法的不变性。一旦被设置为false, 则之后就不能再更改了

普通对象的内部方法如下表:

Internal MethodsDescription
[[GetPrototypeOf]]确定为该对象提供继承属性的对象。空值表示没有继承的属性。 内部指向对象O槽O.[[Prototype]]
[[SetPrototypeOf]]将此对象与提供继承属性的另一个对象相关联。传递null表示没有继承的属性。返回true表示操作成功完成,或返回false表示操作不成功。
[[IsExtensible]]确定是否允许向此对象添加其他属性。
[[preventExtensible]]控制是否可以向此对象添加新属性。如果操作成功,则返回true;如果操作不成功,则返回false。
[[GetOwnProperty]]返回键为propertyKey的此对象的自有属性的属性描述符,如果不存在此类属性,则返回undefined。
[[DefineOwnProperty]]创建或更改其键为propertyKey的自有属性,使其状态由PropertyDescriptor描述。如果成功创建/更新该属性,则返回true;如果无法创建或更新该属性,则返回false。
[[HasProperty]]返回一个布尔值,指示此对象是否已经拥有密钥为propertyKey的自有或继承属性。
[[Get]]从该对象返回键为propertyKey的属性的值。如果必须执行任何ECMAScript代码来检索属性值,则在评估代码时将Receiver用作this值。
[[Set]]将键为propertyKey的属性的值设置为value。如果必须执行任何ECMAScript代码来设置属性值,则在评估代码时将Receiver用作this值。如果属性值已设置,则返回true;如果无法设置,则返回false。
[[Delete]]从此对象中删除键为propertyKey的own属性。如果属性未被删除并且仍然存在,则返回false。如果属性已被删除或不存在,则返回true。
[[OwnPropertyKeys]]返回一个列表,其元素都是对象自己的属性键。
OrdinaryObjectCreate静态方法以一个现有对象作为原型,创建一个新对象。
OrdinaryCreateFromConstructor静态方法以一个现有构造函数的原型作为原型,创建一个新对象。
GetPrototypeFromConstructor查看构造函数是否有原型对象,有则返回,无则返回入参默认原型
RequireInternalSlot判断入参对象O是否是对象或者有内部槽,无则抛出异常

Function Objects

ECMAScript 函数对象封装了在词法环境中闭包的参数化代码,并且进行动态的评估。 函数对象也是一个普通的对象,具有普通对象的插槽和内部方法,除了[[Extensible]][[Prototype]] 之外,还具有以下的内部插槽。

Internal SlotTypeDescription
[[Environment]]Environment Record