Object 对象
Object 对象 是 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);
Reflect.ownKeys(obj)
:
4.1 - 返回一个包括对象自身属性(不包括继承属性)的数组,包括所有属性的键,无论它们是可枚举或不可枚举的。
- 返回的数组包括对象的符号属性(Symbol properties)和字符串属性(String properties)。
- 还包括不可配置的属性(non-configurable properties),而其他两种方法不会列出这些属性。
- 如果
obj
为null
或undefined
,将会抛出一个TypeError
。
Object.keys(obj)
:
4.2 - 返回一个包括对象自身的可枚举字符串属性的数组。
- 不包括不可枚举属性,也不包括符号属性。
- 如果
obj
为null
或undefined
,不会抛出错误,而是返回一个空数组。
Object.getOwnPropertyNames(obj)
:
4.3 - 返回一个包括对象自身的所有字符串属性的数组,不仅包括可枚举属性,还包括不可枚举属性。
- 不包括符号属性。
- 如果
obj
为null
或undefined
,不会抛出错误,而是返回一个空数组。
Object.getOwnPropertySymbols(obj)
4.4 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)
只返回可枚举字符串属性,