对象

Object 类型代表 JavaScript 的数据类型 之一。它用于存储各种带键的集合和更复杂的实体。可以使用 Object() 构造函数或 对象初始值设定项/文字语法

¥The Object type represents one of JavaScript's data types. It is used to store various keyed collections and more complex entities. Objects can be created using the Object() constructor or the object initializer / literal syntax.

描述

¥Description

JavaScript 中几乎所有 objects 都是 Object 的实例;典型的对象从 Object.prototype 继承属性(包括方法),尽管这些属性可能被隐藏(也称为覆盖)。唯一不从 Object.prototype 继承的对象是具有 null 原型机 的对象,或者是其他 null 原型对象的后代。

¥Nearly all objects in JavaScript are instances of Object; a typical object inherits properties (including methods) from Object.prototype, although these properties may be shadowed (a.k.a. overridden). The only objects that don't inherit from Object.prototype are those with null prototype, or descended from other null prototype objects.

所有对象都可以通过原型链看到对 Object.prototype 对象的更改,除非受这些更改影响的属性和方法沿着原型链进一步被覆盖。这提供了一种非常强大但有潜在危险的机制来覆盖或扩展对象行为。为了更安全,Object.prototype 是核心 JavaScript 语言中唯一具有 不可变原型 的对象 - Object.prototype 的原型始终是 null 且不可更改。

¥Changes to the Object.prototype object are seen by all objects through prototype chaining, unless the properties and methods subject to those changes are overridden further along the prototype chain. This provides a very powerful although potentially dangerous mechanism to override or extend object behavior. To make it more secure, Object.prototype is the only object in the core JavaScript language that has immutable prototype — the prototype of Object.prototype is always null and not changeable.

对象原型属性

¥Object prototype properties

你应该避免直接从实例调用任何 Object.prototype 方法,尤其是那些不打算成为多态的方法(即只有其初始行为才有意义,并且没有下降的对象可以以有意义的方式覆盖它)。从 Object.prototype 继承的所有对象都可以定义一个具有相同名称的自定义属性,但其语义与你期望的完全不同。而且,这些属性并没有被 null-原型对象 继承。所有用于处理对象的现代 JavaScript 实用程序都是 static。进一步来说:

¥You should avoid calling any Object.prototype method directly from the instance, especially those that are not intended to be polymorphic (i.e. only its initial behavior makes sense and no descending object could override it in a meaningful way). All objects descending from Object.prototype may define a custom own property that has the same name, but with entirely different semantics from what you expect. Furthermore, these properties are not inherited by null-prototype objects. All modern JavaScript utilities for working with objects are static. More specifically:

如果不存在语义上等效的静态方法,或者如果你确实想使用 Object.prototype 方法,则应该直接对目标对象上的 Object.prototype 方法进行 call() 操作,以防止对象具有产生意外结果的重写属性 。

¥In case where a semantically equivalent static method doesn't exist, or if you really want to use the Object.prototype method, you should directly call() the Object.prototype method on your target object instead, to prevent the object from having an overriding property that produces unexpected results.

js
const obj = {
  foo: 1,
  // You should not define such a method on your own object,
  // but you may not be able to prevent it from happening if
  // you are receiving the object from external input
  propertyIsEnumerable() {
    return false;
  },
};

obj.propertyIsEnumerable("foo"); // false; unexpected result
Object.prototype.propertyIsEnumerable.call(obj, "foo"); // true; expected result

从对象中删除属性

¥Deleting a property from an object

对象本身没有任何方法可以删除自己的属性(例如 Map.prototype.delete())。为此,必须使用 delete 运算符。

¥There isn't any method in an Object itself to delete its own properties (such as Map.prototype.delete()). To do so, one must use the delete operator.

空原型对象

¥null-prototype objects

JavaScript 中几乎所有对象最终都继承自 Object.prototype(参见 继承和原型链)。但是,你可以使用 Object.create(null)对象初始值设定项语法__proto__: null 创建 null 原型对象(注意:对象文本中的 __proto__ 键与已弃用的 Object.prototype.__proto__ 属性不同)。你还可以通过调用 Object.setPrototypeOf(obj, null) 将现有对象的原型更改为 null

¥Almost all objects in JavaScript ultimately inherit from Object.prototype (see inheritance and the prototype chain). However, you may create null-prototype objects using Object.create(null) or the object initializer syntax with __proto__: null (note: the __proto__ key in object literals is different from the deprecated Object.prototype.__proto__ property). You can also change the prototype of an existing object to null by calling Object.setPrototypeOf(obj, null).

js
const obj = Object.create(null);
const obj2 = { __proto__: null };

具有 null 原型的对象可能会以意想不到的方式运行,因为它不从 Object.prototype 继承任何对象方法。在调试时尤其如此,因为常见的对象属性转换/检测实用函数可能会生成错误或丢失信息(特别是在使用忽略错误的静默错误陷阱时)。

¥An object with a null prototype can behave in unexpected ways, because it doesn't inherit any object methods from Object.prototype. This is especially true when debugging, since common object-property converting/detecting utility functions may generate errors, or lose information (especially if using silent error-traps that ignore errors).

例如,缺少 Object.prototype.toString() 通常会使调试变得困难:

¥For example, the lack of Object.prototype.toString() often makes debugging intractable:

js
const normalObj = {}; // create a normal object
const nullProtoObj = Object.create(null); // create an object with "null" prototype

console.log(`normalObj is: ${normalObj}`); // shows "normalObj is: [object Object]"
console.log(`nullProtoObj is: ${nullProtoObj}`); // throws error: Cannot convert object to primitive value

alert(normalObj); // shows [object Object]
alert(nullProtoObj); // throws error: Cannot convert object to primitive value

其他方法也会失败。

¥Other methods will fail as well.

js
normalObj.valueOf(); // shows {}
nullProtoObj.valueOf(); // throws error: nullProtoObj.valueOf is not a function

normalObj.hasOwnProperty("p"); // shows "true"
nullProtoObj.hasOwnProperty("p"); // throws error: nullProtoObj.hasOwnProperty is not a function

normalObj.constructor; // shows "Object() { [native code] }"
nullProtoObj.constructor; // shows "undefined"

我们可以通过将 toString 方法赋值为 1,将其添加回空原型对象:

¥We can add the toString method back to the null-prototype object by assigning it one:

js
nullProtoObj.toString = Object.prototype.toString; // since new object lacks toString, add the original generic one back

console.log(nullProtoObj.toString()); // shows "[object Object]"
console.log(`nullProtoObj is: ${nullProtoObj}`); // shows "nullProtoObj is: [object Object]"

与普通对象(其中 toString() 位于对象原型上)不同,这里的 toString() 方法是 nullProtoObj 自己的属性。这是因为 nullProtoObj 没有(null)原型。

¥Unlike normal objects, in which toString() is on the object's prototype, the toString() method here is an own property of nullProtoObj. This is because nullProtoObj has no (null) prototype.

你还可以使用 Object.setPrototypeOf(nullProtoObj, Object.prototype) 将空原型对象恢复为普通对象。

¥You can also revert a null-prototype object back to an ordinary object using Object.setPrototypeOf(nullProtoObj, Object.prototype).

在实践中,具有 null 原型的对象通常被用作 maps 的廉价替代品。Object.prototype 属性的存在会导致一些错误:

¥In practice, objects with null prototype are usually used as a cheap substitute for maps. The presence of Object.prototype properties will cause some bugs:

js
const ages = { alice: 18, bob: 27 };

function hasPerson(name) {
  return name in ages;
}

function getAge(name) {
  return ages[name];
}

hasPerson("hasOwnProperty"); // true
getAge("toString"); // [Function: toString]

使用空原型对象可以消除这种危险,而不会给 hasPersongetAge 函数带来太多的复杂性:

¥Using a null-prototype object removes this hazard without introducing too much complexity to the hasPerson and getAge functions:

js
const ages = Object.create(null, {
  alice: { value: 18, enumerable: true },
  bob: { value: 27, enumerable: true },
});

hasPerson("hasOwnProperty"); // false
getAge("toString"); // undefined

在这种情况下,添加任何方法都应谨慎进行,因为它们可能与存储为数据的其他键值对混淆。

¥In such case, the addition of any method should be done cautiously, as they can be confused with the other key-value pairs stored as data.

让你的对象不继承 Object.prototype 也可以防止原型污染攻击。如果恶意脚本向 Object.prototype 添加属性,则程序中的每个对象都可以访问该属性,但原型为空的对象除外。

¥Making your object not inherit from Object.prototype also prevents prototype pollution attacks. If a malicious script adds a property to Object.prototype, it will be accessible on every object in your program, except objects that have null prototype.

js
const user = {};

// A malicious script:
Object.prototype.authenticated = true;

// Unexpectedly allowing unauthenticated user to pass through
if (user.authenticated) {
  // access confidential data
}

JavaScript 还具有生成 null 原型对象的内置 API,尤其是那些使用对象作为临时键值集合的对象。例如:

¥JavaScript also has built-in APIs that produce null-prototype objects, especially those that use objects as ad hoc key-value collections. For example:

术语“null 原型对象”通常还包括其原型链中没有 Object.prototype 的任何对象。使用类时可以使用 extends null 创建此类对象。

¥The term "null-prototype object" often also includes any object without Object.prototype in its prototype chain. Such objects can be created with extends null when using classes.

对象强制

¥Object coercion

许多期望对象首先将其参数强制为对象的内置操作。操作 可概括如下:

¥Many built-in operations that expect objects first coerce their arguments to objects. The operation can be summarized as follows:

在 JavaScript 中,有两种方法可以达到几乎相同的效果。

¥There are two ways to achieve nearly the same effect in JavaScript.

  • Object.prototype.valueOf()Object.prototype.valueOf.call(x) 完全执行上面解释的对象强制步骤来转换 x
  • Object() 功能:Object(x) 使用相同的算法来转换 x,只不过 undefinednull 不会抛出 TypeError,而是返回一个普通对象。

使用对象强制的地方包括:

¥Places that use object coercion include:

  • for...in 循环的 object 参数。
  • Array 方法的 this 值。
  • Object 方法的参数,例如 Object.keys()
  • 当对基元值访问属性时自动装箱,因为基元没有属性。
  • 调用非严格函数时的 this 值。基元被装箱,而 nullundefined 被替换为 全局对象

转换为原语 不同,对象强制过程本身无法以任何方式观察到,因为它不会像 toStringvalueOf 方法那样调用自定义代码。

¥Unlike conversion to primitives, the object coercion process itself is not observable in any way, since it doesn't invoke custom code like toString or valueOf methods.

构造函数

¥Constructor

Object()

将输入转换为对象。

静态方法

¥Static methods

Object.assign()

将一个或多个源对象的所有可枚举自身属性的值复制到目标对象。

Object.create()

使用指定的原型对象和属性创建一个新对象。

Object.defineProperties()

将给定描述符描述的命名属性添加到对象中。

Object.defineProperty()

将给定描述符描述的命名属性添加到对象。

Object.entries()

返回一个数组,其中包含给定对象自己的可枚举字符串属性的所有 [key, value] 对。

Object.freeze()

冻结一个对象。其他代码无法删除或更改其属性。

Object.fromEntries()

[key, value] 对的可迭代中返回一个新对象。(这与 Object.entries 相反)。

Object.getOwnPropertyDescriptor()

返回对象上命名属性的属性描述符。

Object.getOwnPropertyDescriptors()

返回一个包含对象所有自己的属性描述符的对象。

Object.getOwnPropertyNames()

返回一个数组,其中包含给定对象自己的所有可枚举和不可枚举属性的名称。

Object.getOwnPropertySymbols()

返回直接在给定对象上找到的所有符号属性的数组。

Object.getPrototypeOf()

返回指定对象的原型(内部 [[Prototype]] 属性)。

Object.groupBy()

根据提供的回调函数返回的字符串值对给定可迭代的元素进行分组。返回的对象对于每个组都有单独的属性,其中包含包含该组中元素的数组。

Object.hasOwn()

如果指定对象具有指定的属性作为其自己的属性,则返回 true;如果该属性是继承的或不存在,则返回 false

Object.is()

比较两个值是否相同。等于所有 NaN 值(不同于 == 使用的 IsLooselyEqual=== 使用的 IsStrictlyEqual)。

Object.isExtensible()

确定是否允许扩展对象。

Object.isFrozen()

确定对象是否被冻结。

Object.isSealed()

确定对象是否被密封。

Object.keys()

返回一个数组,其中包含给定对象自己的所有可枚举字符串属性的名称。

Object.preventExtensions()

防止对象的任何扩展。

Object.seal()

防止其他代码删除对象的属性。

Object.setPrototypeOf()

设置对象的原型(其内部 [[Prototype]] 属性)。

Object.values()

返回一个数组,其中包含与给定对象自己的所有可枚举字符串属性相对应的值。

实例属性

¥Instance properties

这些属性在 Object.prototype 上定义并由所有 Object 实例共享。

¥These properties are defined on Object.prototype and shared by all Object instances.

Object.prototype.__proto__ Deprecated

指向实例化对象时用作原型的对象。

Object.prototype.constructor

创建实例对象的构造函数。对于普通 Object 实例,初始值为 Object 构造函数。其他构造函数的实例均从各自的 Constructor.prototype 对象继承 constructor 属性。

实例方法

¥Instance methods

Object.prototype.__defineGetter__() Deprecated

将函数与属性关联起来,当访问该属性时,执行该函数并返回其返回值。

Object.prototype.__defineSetter__() Deprecated

将函数与属性关联起来,设置后执行修改该属性的函数。

Object.prototype.__lookupGetter__() Deprecated

返回作为 getter 绑定到指定属性的函数。

Object.prototype.__lookupSetter__() Deprecated

返回作为指定属性的 setter 绑定的函数。

Object.prototype.hasOwnProperty()

返回一个布尔值,指示对象是否包含指定属性作为该对象的直接属性并且不通过原型链继承。

Object.prototype.isPrototypeOf()

返回一个布尔值,指示调用此方法的对象是否在指定对象的原型链中。

Object.prototype.propertyIsEnumerable()

返回一个布尔值,指示指定的属性是否是对象的 可枚举自己的 属性。

Object.prototype.toLocaleString()

调用 toString()

Object.prototype.toString()

返回对象的字符串表示形式。

Object.prototype.valueOf()

返回指定对象的原始值。

示例

¥Examples

构造空对象

¥Constructing empty objects

以下示例使用带有不同参数的 new 关键字创建空对象:

¥The following example creates empty objects using the new keyword with different arguments:

js
const o1 = new Object();
const o2 = new Object(undefined);
const o3 = new Object(null);

使用 Object() 构造函数将基元转换为各自类型的对象

¥Using Object() constructor to turn primitives into an Object of their respective type

你可以使用 Object() 构造函数创建原始值的对象封装器。

¥You can use the Object() constructor to create an object wrapper of a primitive value.

以下示例创建变量 o1o2,它们是存储 BooleanBigInt 值的对象:

¥The following examples create variables o1 and o2 which are objects storing Boolean and BigInt values:

js
// Equivalent to const o1 = new Boolean(true)
const o1 = new Object(true);

// No equivalent because BigInt() can't be called as a constructor,
// and calling it as a regular function won't create an object
const o2 = new Object(1n);

对象原型

¥Object prototypes

更改现有 Object.prototype 方法的行为时,请考虑通过在现有逻辑之前或之后封装扩展来注入代码。例如,此(未经测试的)代码将在执行内置逻辑或其他人的扩展之前有条件地执行自定义逻辑。

¥When altering the behavior of existing Object.prototype methods, consider injecting code by wrapping your extension before or after the existing logic. For example, this (untested) code will pre-conditionally execute custom logic before the built-in logic or someone else's extension is executed.

当使用钩子修改原型时,通过在函数上调用 apply()this 和参数(调用状态)传递给当前行为。该模式可用于任何原型,例如 Node.prototypeFunction.prototype 等。

¥When modifying prototypes with hooks, pass this and the arguments (the call state) to the current behavior by calling apply() on the function. This pattern can be used for any prototype, such as Node.prototype, Function.prototype, etc.

js
const current = Object.prototype.valueOf;

// Since my property "-prop-value" is cross-cutting and isn't always
// on the same prototype chain, I want to modify Object.prototype:
Object.prototype.valueOf = function (...args) {
  if (Object.hasOwn(this, "-prop-value")) {
    return this["-prop-value"];
  } else {
    // It doesn't look like one of my objects, so let's fall back on
    // the default behavior by reproducing the current behavior as best we can.
    // The apply behaves like "super" in some other languages.
    // Even though valueOf() doesn't take arguments, some other hook may.
    return current.apply(this, args);
  }
};

警告:修改任何内置构造函数的 prototype 属性被认为是一种不好的做法,并且存在向前兼容性的风险。

¥Warning: Modifying the prototype property of any built-in constructor is considered a bad practice and risks forward compatibility.

你可以在 继承和原型链 中阅读有关原型的更多信息。

¥You can read more about prototypes in Inheritance and the prototype chain.

规范

Specification
ECMAScript Language Specification
# sec-object-objects

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看