Skip to main content

Object 类型

ObjectJavaScript 的一种数据类型, 它用于存储各种键值集合和更复杂的实体。 可以通过 Object() 构造函数或者使用对象字面量的方式创建对象。

描述

JavaScript中,几乎所有的对象都是 Object 的实例;一个典型的对象从Object.prototype继承属性(包括方法)。

null 原型对象

Object.create(null) 创建出来的对象不会继承Object.prototype的属性和方法。 这在调试时尤其需要注意,因为常见的对象属性转换/检测实用方法可能会产生错误或丢失信息

Object.prototype.toString() 方法的缺失通常会使得调试变得困难:

const normalObj = {}; // 创建一个普通对象
const nullProtoObj = Object.create(null); // 创建一个 "null" 原型对象

console.log(`normalObj 是:${normalObj}`); // normalObj 是:[object Object]
console.log(`nullProtoObj 是:${nullProtoObj}`); // TypeError: Cannot convert object to primitive value

在实践中,null 原型对象通常被用作 map 的简单替代品。由于存在 Object.prototype 属性,会导致一些错误:

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

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

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

hasPerson("hasOwnProperty"); // true
getAge("toString"); // ƒ toString() { [native code] }

使用一个 null 原型对象可以消除这种风险,同时不会令 hasPerson 和 getAge 函数变得复杂:

const ages = Object.create(null, {
alice: { value: 18, enumerable: true },
bob: { value: 27, enumerable: true },
});
hasPerson("hasOwnProperty"); // false
getAge("toString"); // undefined

从对象中删除属性

一个对象本身没有任何方法可以,(像 Map.prototype.delete() 一样)删除自己的属性。要删除一个对象的属性,必须使用 delete运算符

每个 Object 实例都会有如下的属性和方法:

constructor

用于创建当前对象的函数 在之前的例子中 这个属性的值就是Object()函数。

hasOwnProperty(prototypeName)

hasOwnProperty()方法返回一个布尔值,用于判断当前实例对象(不是原型),是否存在给定的属性名称。

const object1 = {};
object1.property1 = 42;

console.log(object1.hasOwnProperty('property1')) // true;
console.log(object1.hasOwnProperty('toString')) // false;
console.log(object1.hasOwnProperty('hasOwnProperty')) // false;

参数

  • prop

    要测试的属性的字符串名称或者 Symbol

  • 返回值

    如果对象有指定属性作为自有属性,则返回 true,否则返回 false

描述

如果指定的属性是对象的直接属性——即使值为 null 或者 undefinedhasOwnProperty() 方法也会返回 true。如果属性是继承的,或者根本没有声明该属性,则该方法返回 false

in运算符不同的是,该方法不会在对象原型链中检查指定的属性

使用 hasOwnProperty 测试自有属性是否存在

以下代码展示了如何确定 example 对象包含了一个名为 prop 的属性。

const example = {};
example.hasOwnProperty("prop"); // false

example.prop = "exists";
example.hasOwnProperty("prop"); // true

example.prop = null;
example.hasOwnProperty("prop"); // true

example.prop = undefined;
example.hasOwnProperty("prop"); // true

直接属性 vs 继承属性

以下示例区分了直接属性和通过原型链继承的属性:

const example = {};
example.prop = "exists";

// `hasOwnProperty` 仅对直接属性返回 true:
example.hasOwnProperty("prop"); // true
example.hasOwnProperty("toString"); // false
example.hasOwnProperty("hasOwnProperty"); // false

// 对于直接或继承的属性,`in` 运算符将返回 true:
"prop" in example; // true
"toString" in example; // true
"hasOwnProperty" in example; // true

由 Object.create(null) 创建的对象

const foo = Object.create(null);
foo.prop = "exists";
foo.hasOwnProperty("prop"); // Uncaught TypeError: foo.hasOwnProperty is not a function

遍历对象的属性

Object.prototype.gender = '男';

const buz = {
fog: "stack",
};

// 如果属性挂载对象的原型上 会被for..of() 遍历出来
for (const name in buz) {
if (buz.hasOwnProperty(name)) {
console.log(`this is fog (${name}) for sure. Value: ${buz[name]}`);
} else {
console.log(name); // toString 或其他的方法等
}
}

// this is fog (fog) for sure. Value:stack
// gender

isPrototypeOf()

isPrototypeOf()方法用于检查一个对象是否存在另一个对象的原型链中。

function Foo() {}
function Bar() {}

Bar.prototype = Object.create(Foo.prototype);

const bar = new Bar();

console.log(Foo.prototype.isPrototypeOf(bar)); // true
console.log(Bar.prototype.isPrototypeOf(bar)); // true

参数

  • object

    要搜索其原型链的对象。

  • 返回值

    一个布尔值,指示调用 isPrototypeOf() 方法的对象(即 this)是否位于 object 的原型链中。 当 object 不是一个对象(即基本类型)时,直接返回 false

描述

isPrototypeOf()方法允许你检查对象是否存在于另一个对象的原型链中,如果作为参数的object不是对象(是基本类型), 则直接返回 false。 否则, this 值被转换为对象 并且在object的原型链中搜索 this的值 直到到达原型链的末端或者找到 this 为止

示例

class Foo {}
class Bar extends Foo {}
class Baz extends Bar {}


const foo = new Foo();
const bar = new Bar();
const baz = new Baz();

// 原型链
// Foo=>Object
// Bar=>Foo=>Object
// Baz=>Bar=>Foo=>Object

console.log(Baz.prototype.isPrototypeOf(baz)); // true
console.log(Baz.prototype.isPrototypeOf(bar)); // false
console.log(Baz.prototype.isPrototypeOf(foo)); // false
console.log(Bar.prototype.isPrototypeOf(baz)); // true
console.log(Bar.prototype.isPrototypeOf(baz)); // true
console.log(Bar.prototype.isPrototypeOf(foo)); // false
console.log(Foo.prototype.isPrototypeOf(baz)); // true
console.log(Foo.prototype.isPrototypeOf(bar)); // true
console.log(Object.prototype.isPrototypeOf(baz)); // true

propertyIsEnumerable(prototypeName)

propertyIsEnumerable() 方法返回一个布尔值,表示指定的属性是否是对象的可枚举自有属性。

const object1 = {};
const array1 = [];
object1.property1 = 42;
array1[0] = 42;

console.log(object1.propertyIsEnumerable('property1'));
// Expected output: true

console.log(array1.propertyIsEnumerable(0));
// Expected output: true

console.log(array1.propertyIsEnumerable('length'));
// Expected output: false

参数

prop

需要测试的属性名,可以是字符串或 Symbol

返回值

一个布尔值,指示指定 的属性是否可枚举并且是对象自有的属性。

描述

所有继承自 Object.prototype(即除了 null 原型对象之外的所有对象),都继承了 propertyIsEnumerable()方法用于检查一个对象是否存在另一个对象的原型链中。 该方法判断指定的属性() (字符串或 symbol 值)是否是对象的可枚举自有属性。如果对象没有指定的属性,则该方法返回 false

toLocalString()

toLocalString() 方法返回一个表示对象的字符串,该方法旨在由派生对象重写,以达到其特定于语言环境的目的。 用于将对象转换为本地化的字符串表示形式的方法。不同类型的对象可能会有不同的实现方式

// 数字(Number)
// 对于数字,toLocaleString 方法会根据指定或默认的区域设置(locale)将数字格式化为本地化的字符串。
const number = 1234567.89;

console.log(number.toLocaleString("en-US")); // "1,234,567.89" (美国英语)
console.log(number.toLocaleString("de-DE")); // "1.234.567,89" (德国德语)
console.log(number.toLocaleString("zh-CN")); // "1,234,567.89" (中国中文)

// 日期(Date)
// 对于日期对象,toLocaleString 方法会根据指定或默认的区域设置将日期和时间格式化为本地化的字符串。
console.log(date.toLocaleString("en-US")); // "6/20/2024, 7:03:51 AM" (美国英语)
console.log(date.toLocaleString("de-DE")); // "20.6.2024, 07:03:51" (德国德语)
console.log(date.toLocaleString("zh-CN")); // "2024/6/20 下午7:03:51" (中国中文)

// 数组(Array)
// 对于数组,toLocaleString 方法会对每个元素调用其 toLocaleString 方法,然后将结果连接成一个字符串,使用逗号分隔。
const array = [1234.56, new Date(), "Hello"];

console.log(array.toLocaleString("en-US")); // "1,234.56, 6/20/2024, 7:03:51 AM, Hello" (美国英语)
console.log(array.toLocaleString("de-DE")); // "1.234,56, 20.6.2024, 07:03:51, Hello" (德国德语)

// 自定义对象
// 对于自定义对象,如果没有覆盖 toLocaleString 方法,则默认调用 Object.prototype.toLocaleString,它会返回与 toString 相同的结果。
const obj = {
toString() {
return "Custom Object";
},
};

console.log(obj.toLocaleString()); // "Custom Object"

toString()

toString() 方法返回一个表示该对象的字符串。该方法旨在重写(自定义)派生类对象的类型转换的逻辑

参数

默认情况下,toString()不接受任何参数。然而,继承自object的对象可能用于他们自己的实现重写它,这些实现可以接受参数,例如 Number.prototype.toString()BigInt.prototype.toString() 方法可以接受一个可选的 radix 参数

const string = "123";
const number = 123;
const array = [1, 2, 3, 4, 5, 6, 7];
const object = {};
const boolean = true;
const a = +[1];

string.toString(); // 123
number.toString(16); // 7b
array.toString(); // 1,2,3,4,5,6,7
object.toString(); // [object Object]
boolean.toString(); // 'true'
console.log(a); // 1

返回值

一个表示该对象的字符串

描述

JavaScript 调用 toString 方法将对象转换为一个原始值。

该方法有字符串转换优先调用,但是数字的强制转换原始值的强制转换会优先调用valueOf()。 如果 valueOf()返回的不是基础数据类型。则会调用 toString()方法。

要将基本的 Object.prototype.toString()用于重写的对象(或者在 nullundefined 上调用它), 你需要在它上面调用Function.prototype.call()或者Function.prototype.apply(),将要检查的对象作为第一个参数传递

const arr = [1, 2, 3];

arr.toString() // 1,2,3
Object.prototype.toString.call(arr) // [object Array]
Object.prototype.toString.call(null) // [object Null]
Object.prototype.toString.call(undefined) // [object Undefined]

valueOf()

Object 实例的 valueOf() 方法将 this 值转换为对象 , 该方法旨在被派生对象重写,以实现自定义类型转换逻辑。

返回值

转换成对象的 this

描述

JavaScript调用 valueOf 方法来讲对象转换成基本类型值。

强制数字类型转换强制基本类型转换优先会调用该方法,而强制字符串转换会优先调用 toString();

示例

使用 valueOf()

基本的 valueOf() 方法返回 this 值本身,如果尚未转换为对象,则转换成对象。因此,任何基本类型转换算法都不会使用它的返回值。

const obj = { foo: 1 };
console.log(obj.valueOf() === obj); // true

对对象使用一元加运算符

一元加(+) 对其操作数进行强制数字转换,对于大多数没有 @@toPrimitive 的对象,这意味着调用其 valueOf()。 但是,如果对象没有自定义的 valueOf() 方法,则基本实现将导致忽略 valueOf(),而使用 toString() 的返回值。

+new Date(); // 当前时间戳;与 new Date().getTime() 相同
+{}; // NaN 相当于Number('[object Object]')
+[]; // 0 相当于Number('')
+[1]; // 1 相当于Number(1)
+[1, 2]; // NaN 相当于Number("1,2")
+new Set([1]); // NaN 相当于Number("[object Set]")
+{ valueOf: () => 42 }; // 42