对象
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:
valueOf()
、toString()
和toLocaleString()
是多态存在的,你应该期望对象以合理的行为定义自己的实现,因此你可以将它们作为实例方法调用。但是,valueOf()
和toString()
通常通过 类型转换 隐式调用,你不需要在代码中自己调用它们。__defineGetter__()
、__defineSetter__()
、__lookupGetter__()
和__lookupSetter__()
已弃用,不应使用。请改用静态替代方案Object.defineProperty()
和Object.getOwnPropertyDescriptor()
。__proto__
属性已弃用,不应使用。Object.getPrototypeOf()
和Object.setPrototypeOf()
替代方法是静态方法。propertyIsEnumerable()
和hasOwnProperty()
方法可以分别替换为Object.getOwnPropertyDescriptor()
和Object.hasOwn()
静态方法。- 如果你要检查构造函数的
prototype
属性,则isPrototypeOf()
方法通常可以替换为instanceof
。
如果不存在语义上等效的静态方法,或者如果你确实想使用 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.
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)
.
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:
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.
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:
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:
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]
使用空原型对象可以消除这种危险,而不会给 hasPerson
和 getAge
函数带来太多的复杂性:
¥Using a null-prototype object removes this hazard without introducing too much complexity to the hasPerson
and getAge
functions:
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.
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:
Object.groupBy()
的返回值RegExp.prototype.exec()
结果的groups
和indices.groups
属性Array.prototype[Symbol.unscopables]
(所有[Symbol.unscopables]
对象都应该有null
原型)import.meta
- 模块命名空间对象,通过
import * as ns from "module";
或import()
获取
术语“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
,只不过undefined
和null
不会抛出TypeError
,而是返回一个普通对象。
使用对象强制的地方包括:
¥Places that use object coercion include:
for...in
循环的object
参数。Array
方法的this
值。Object
方法的参数,例如Object.keys()
。- 当对基元值访问属性时自动装箱,因为基元没有属性。
- 调用非严格函数时的
this
值。基元被装箱,而null
和undefined
被替换为 全局对象。
与 转换为原语 不同,对象强制过程本身无法以任何方式观察到,因为它不会像 toString
或 valueOf
方法那样调用自定义代码。
¥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.
构造函数
静态方法
¥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()
-
返回指定对象的原始值。
示例
构造空对象
使用 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.
以下示例创建变量 o1
和 o2
,它们是存储 Boolean
和 BigInt
值的对象:
¥The following examples create variables o1
and o2
which are objects storing Boolean
and BigInt
values:
// 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.prototype
、Function.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.
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 |
浏览器兼容性
BCD tables only load in the browser
也可以看看
¥See also