Object 对象

Object 对象open in new window 是 JavaScript 的一种 数据类型 。

它用于存储各种键值集合和更复杂的实体。

Objects 可以通过 Object() 构造函数或者使用 对象字面量 的方式创建

1. 关于对象的规则设置

1.1 冻结

冻结:Object.freeze(obj);

判断是否冻结:Object.isFrozen(obj) => Boolean

被冻结的对象不能对其成员进行增加、删除、修改、数据劫持(Object.defineProperty

let obj = { x: 10, y: 20 };

// 对对象obj进行冻结
Object.freeze(obj);

// 判断对象是否被冻结,输出结果为true
console.log(Object.isFrozen(obj));

// 对对象进行操作时,将会报错
// caught TypeError: Cannot assign to read only property 'x' of object '#<Object>'
obj.x = 1000;
obj.y = 2000;

1.2 密封

密封:Object.seal(obj);

判断是否被密封:Object.isSealed(obj) => Boolean

被密封的对象不能对其成员进行增加、删除、数据劫持(Object.defineProperty),可以修改对象成员变量

let obj = { x: 10, y: 20 };

// 对对象obj进行密封
Object.seal(obj);

// 判断对象是否被密封,输出结果为true
console.log(Object.isSealed(obj));

// 对此对象进行修改时不会报错
obj.x = 1000;
obj.y = 2000;

// 对对象进行增加成员变量、删除操作时,将会报错
// Uncaught TypeError: Cannot add property z, object is not extensible
obj.z = 20;

// caught TypeError: Cannot delete property 'x' of #<Object>
delete obj.x;

1.3 不可拓展

禁止可拓展:Object.preventExtensions(obj);

判断是否可拓展:Object.isExtensible(obj) => Boolean

被密封的对象可以对其成员修改、删除、数据劫持(Object.defineProperty),不可添加成员变量

let obj = { x: 10, y: 20 };

// 对对象obj进行禁止可拓展
Object.preventExtensions(obj);

// 判断对象是否可拓展,输出结果为true
console.log(Object.isExtensible(obj));

// 对此对象进行修改时不会报错
obj.x = 1000;
obj.y = 2000;

// 对此对象进行删除时不会报错
delete obj.x;

// 对对象进行增加成员变量操作时,将会报错
// Uncaught TypeError: Cannot add property z, object is not extensible
obj.z = 20;

1.4 特别注意

  • 被冻结的对象肯定是密封的与不可拓展的
  • 被密封的对象肯定也是不可拓展的

在 ES5 中,如果参数不是一个对象类型,将抛出一个 TypeError 异常。

在 ES2015 中,非对象参数将被视为一个冻结的普通对象,因此会返回 true

Object.isFrozen(1);
// TypeError: 1 is not an object (ES5 code)

Object.isFrozen(1);
// true                          (ES2015 code)

2. Object.defineProperty

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

  • configurable

当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。 默认为 false。

  • enumerable

当且仅当该属性的 enumerable 键值为 true 时,该属性才会出现在对象的枚举属性中。 默认为 false。

数据描述符还具有以下可选键值:

  • value

该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。 默认为 undefined。

  • writable

当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符 (en-US)改变。 默认为 false。

存取描述符还具有以下可选键值:

  • get

属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的 this 并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。 默认为 undefined。

  • set

属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。 默认为 undefined。

let data = { x: 100 };
let dataProxyer = {};

// dataProxyer对象的x属性值代理了data对象的x属性值
// 1.获取data中的某个key值可以通过dataProxyer的key获取
// 2.修改data中的某个key值可以通过修改dataProxyer的key实现

Object.defineProperty(dataProxyer, "x", {
  get() {
    return data.x;
  },
  set(value) {
    data.x = value;
  },
});

console.log("data.x的初始值为:", data.x);
// data.x的初始值为:100

// 通过数据代理dataProxyer修改了data的x属性的值
dataProxyer.x = 1000;

console.log("通过数据代理修改,data.x的最终值为:", data.x);
// 通过数据代理修改,data.x的最终值为:1000

3.Object.is

Object.is() 方法判断两个值是否为同一个值。

Object.is() 方法判断两个值是否为同一个值,如果满足以下任意条件则两个值相等:

都是 undefined

都是 null

都是 true 或都是 false

都是相同长度、相同字符、按相同顺序排列的字符串

都是相同对象(意味着都是同一个对象的值引用)

都是数字且

都是 +0

都是 -0

都是 NaN

都是同一个值,非零且都不是 NaN

Object.is() 与 == 不同。== 运算符在判断相等前对两边的变量(如果它们不是同一类型)进行强制转换(这种行为将 "" == false 判断为 true),而 Object.is 不会强制转换两边的值。

Object.is() 与 === 也不相同。差别是它们对待有符号的零和 NaN 不同,例如,=== 运算符(也包括 == 运算符)将数字 -0 和 +0 视为相等,而将 Number.NaN 与 NaN 视为不相等。

// Case 1: Evaluation result is the same as using ===
Object.is(25, 25); // true
Object.is("foo", "foo"); // true
Object.is("foo", "bar"); // false
Object.is(null, null); // true
Object.is(undefined, undefined); // true
Object.is(window, window); // true
Object.is([], []); // false
var foo = { a: 1 };
var bar = { a: 1 };
Object.is(foo, foo); // true
Object.is(foo, bar); // false

// Case 2: Signed zero
Object.is(0, -0); // false
Object.is(+0, -0); // false
Object.is(-0, -0); // true
Object.is(0n, -0n); // true

// Case 3: NaN
Object.is(NaN, 0 / 0); // true
Object.is(NaN, Number.NaN); // true

4.Object 属性列举的方法

Reflect.ownKeys(obj)Object.keys(obj)Object.getOwnPropertyNames(obj) 都是用于获取对象的属性名称的方法, 但它们之间存在一些关键差异,主要涉及到它们处理属性的方式和返回结果的不同:

Reflect.ownKeys(obj) >= Object.getOwnPropertyNames(obj) >= Object.keys(obj);

4.1 Reflect.ownKeys(obj):

  • 返回一个包括对象自身属性(不包括继承属性)的数组,包括所有属性的键,无论它们是可枚举或不可枚举的。
  • 返回的数组包括对象的符号属性(Symbol properties)和字符串属性(String properties)。
  • 还包括不可配置的属性(non-configurable properties),而其他两种方法不会列出这些属性。
  • 如果 objnullundefined,将会抛出一个 TypeError

4.2 Object.keys(obj):

  • 返回一个包括对象自身的可枚举字符串属性的数组。
  • 不包括不可枚举属性,也不包括符号属性。
  • 如果 objnullundefined,不会抛出错误,而是返回一个空数组。

4.3 Object.getOwnPropertyNames(obj):

  • 返回一个包括对象自身的所有字符串属性的数组,不仅包括可枚举属性,还包括不可枚举属性。
  • 不包括符号属性。
  • 如果 objnullundefined,不会抛出错误,而是返回一个空数组。

4.4 Object.getOwnPropertySymbols(obj)

Object.getOwnPropertySymbols(obj) 是一个用于获取对象自身的所有符号属性的方法。

它返回一个包含了对象自身的所有符号属性的数组。

符号属性是一种特殊类型的属性,它们的名称是符号 (Symbol) 对象,通常用于定义对象的一些非公开、唯一的属性。

符号属性通常不会被常规的 for...in 循环、Object.keys()Object.getOwnPropertyNames() 所列举,因为它们是隐藏的。

以下是一个示例,演示如何使用 Object.getOwnPropertySymbols(obj)

const obj = {
  [Symbol("a")]: "Symbol Property A",
  [Symbol("b")]: "Symbol Property B",
  name: "John",
};

const symbols = Object.getOwnPropertySymbols(obj);
console.log(symbols); // [Symbol(a), Symbol(b)]

symbols.forEach((symbol) => {
  console.log(obj[symbol]); // 输出 "Symbol Property A" 和 "Symbol Property B"
});

在上面的示例中,Object.getOwnPropertySymbols(obj) 返回一个包含了对象 obj 的两个符号属性 [Symbol(a), Symbol(b)] 的数组。然后,我们可以使用这些符号属性来访问相应的属性值。

需要注意的是,Object.getOwnPropertySymbols(obj) 只返回对象自身的符号属性,而不包括从原型链继承的符号属性。

4.5 for in

for...in 循环用于遍历对象的可枚举属性,包括对象自身的可枚举属性以及从原型链中继承的可枚举属性。

4.6 示例

下面是一个示例,演示了这些方法之间的不同:

const obj = {
  name: "John",
};

Object.defineProperty(obj, "age", {
  value: 30,
  enumerable: false,
});

const symbolKey = Symbol("key");
obj[symbolKey] = "Symbol property";

console.log(Reflect.ownKeys(obj)); // ["name", "age", Symbol(key)]
console.log(Object.getOwnPropertyNames(obj)); // ["name", "age"]
console.log(Object.keys(obj)); // ["name"]

for (let key in obj) {
  console.log(key); // 输出 "name"
}

Reflect.ownKeys(obj) 返回了所有属性,包括可枚举属性、不可枚举属性和符号属性。

Object.getOwnPropertyNames(obj) 返回了所有字符串属性,包括不可枚举属性。

Object.keys(obj) 只返回可枚举字符串属性,

Contributors: masecho