图标说明
- 💥 (sideEffect,该方法有副作用)
- 🗝️ (support String key,该方法的键名支持`String`数据类型)
- 🔑 (support Symbol key,该方法的键名支持`Symbol`数据类型)
- ⛓️ (use prototype chain ,该方法使用了原型链条)
- 遍历原型对象及祖先原型对象时,需要顺着原型链向上实例的创建
// 函数式
Object(any); // Object === Object.prototype.constructor
// 面向对象
new Object(any); // 返回any值对应的包装对象。使用 [new + 类型对象] 这样的面向对象范式
Object.create(null, propDescriptors) // 使用 [对象.属性] 这样的面向对象范式
// 字面量
const object = {}; // 最常用
// object.constructor === Object // true实例的内部属性决定其状态
| ecma | 外部方法 | 内部属性 | 属性描述符 | 表现说明 |
|---|---|---|---|---|
| - | - | [[Extensible]]为true | - | 可以扩展新属性 |
| 5 | Object.preventExtensions(instance💥) | [[Extensible]]为false | - | 不能扩展新属性 |
| 5 | Object.seal(instance💥) | [[Extensible]]为false,[[sealed]]为true | 全部属性描述符改为configurable:false | 不能扩展新属性、不能删除属性、不能重新定义属性 总结,若可写仍然可写,其他都不行 |
| 5 | Object.freeze(instance💥) | [[Extensible]]为false,[[frozen]]为true | 全部属性描述符改为configurable:falsewritable:false | 不能扩展新属性,实例及其属性只读 |
import { describe,test,expect } from "@rstest/core";
const {
preventExtensions, seal, freeze,
isExtensible, isSealed, isFrozen,
getOwnPropertyDescriptor,
} = Object;
/**
* 实验目标
* - 实例的内部属性的检测
* 实验结论
* - 状态`[[extensible]] === true`: isExtensible 为 true
* - 状态`[[sealed]] === true`: isExtensible 为 false,isSealed 为 true,isFrozen 为 false
* - 状态`[[frozen]] === true`: isExtensible 为 false,isSealed 和 isFrozen 为 true
*/
describe("实例状态的检测方法", () => {
test("[[extensible]] === true", () => {
const object = { k: "v" };
expect(isExtensible(object)).toBeTruthy();
expect(isSealed(object)).not.toBeTruthy();
expect(isFrozen(object)).not.toBeTruthy();
});
test("[[extensible]] === false", () => {
const object = { k: "v" };
preventExtensions(object);
expect(isExtensible(object)).not.toBeTruthy();
expect(isSealed(object)).not.toBeTruthy();
expect(isFrozen(object)).not.toBeTruthy();
});
test("[[sealed]] === true", () => {
const object = { k: "v" };
seal(object);
expect(isExtensible(object)).not.toBeTruthy();
expect(isSealed(object)).toBeTruthy();
expect(isFrozen(object)).not.toBeTruthy();
});
test("[[frozen]] === true", () => {
const object = { k: "v" };
freeze(object);
expect(isExtensible(object)).not.toBeTruthy();
expect(isSealed(object)).toBeTruthy();
expect(isFrozen(object)).toBeTruthy();
});
});
/**
* 实验目标
* - 实例内部属性决定了属性描述符
* 实验结论
* - 状态`[[extensible]] === true`: 默认态,允许在实例上添加新属性
* - 状态`[[extensible]] === false`: 阻止在实例上添加新属性,不改变存量属性们的属性描述符
* - 状态`[[sealed]] === true`: 阻止在实例上添加新属性,修改存量属性们的 configurable 为 false,
* - 状态`[[frozen]] === true`: 阻止在实例上添加新属性,修改存量属性们的 configurable 和 writable 为 false,
*/
describe("实例状态的属性标识符", () => {
test("[[extensible]] === true", () => {
const object = { k: "v" };
const propDescriptor = getOwnPropertyDescriptor(object, "k");
const assert = {configurable: true, writable: true,};
expect(propDescriptor).toMatchObject(assert);
});
test("[[extensible]] === false", () => {
const object = { k: "v" };
preventExtensions(object);
const propDescriptor = getOwnPropertyDescriptor(object, "k");
const assert = {configurable: true, writable: true,};
expect(propDescriptor).toMatchObject(assert);
});
test("[[sealed]] === true", () => {
const object = { k: "v" };
seal(object);
const propDescriptor = getOwnPropertyDescriptor(object, "k");
const assert = {configurable: false, writable: true,};
expect(propDescriptor).toMatchObject(assert);
});
test("[[frozen]] === true", () => {
const object = { k: "v" };
freeze(object);
const propDescriptor = getOwnPropertyDescriptor(object, "k");
const assert = {configurable: false, writable: false,};
expect(propDescriptor).toMatchObject(assert);
});
});实例属性的特性由属性描述符(集)控制
| 属性描述符 | 键可删除/重新定义 | 值可修改 | 键值可被检索 |
|---|---|---|---|
configurable | ✅ | ||
writable | ✅ | ||
enumerable | ✅ |
import { describe,test,expect } from "@rstest/core";
const {
preventExtensions, seal, freeze,
isExtensible, isSealed, isFrozen,
getOwnPropertyDescriptor, getOwnPropertyDescriptors,
} = Object;
/**
* configurable - 是否可配置
* - 重新定义属性
* - 删除属性
*/
describe("属性描述符对属性的影响: configurable", () => {
const object = {k: "v"}; // configurable: true, writable: true, enumerable: true,
test("configurable:false", () => {
Object.defineProperty(object, "k", { configurable: false });
expect(() => {
Object.defineProperty(object, "k", { configurable: true });
}).toThrow();
expect(() => {
delete object.k;
}).toThrow();
});
});
/**
* writable - 是否可写
* - 修改属性值
*/
describe("属性描述符对属性的影响: writable", () => {
const object = {k: "v"}; // configurable: true, writable: true, enumerable: true,
test("writable:false", () => {
Object.defineProperty(object, "k", { writable: false });
expect(() => {
object.k = "newV";
}).toThrow();
expect(object.k).toBe("v");
});
});
/**
* enumerable - 是否可枚举
* - for...in/of 语法
* - Object.keys()等接口
* - Object.getOwnPropertyNames() 这是特例
*/
describe("属性描述符对属性的影响: enumerable", () => {
const object = {k: "v"}; // configurable: true, writable: true, enumerable: true,
test("enumerable:false", () => {
Object.defineProperty(object, "k", { enumerable: false });
for(const key in object) {
// 不会遍历到 k
expect(key).not.toBe("k");
}
expect(Object.keys(object)).toHaveLength(0);
expect(Object.getOwnPropertyNames(object)).toHaveLength(1); // 无视不可枚举属性
});
});参数含属性描述符(数据结构)的方法
| ecma | api | describe |
|---|---|---|
| 5 | 🗝️🔑 Object.create(proto[,propDescriptors]) | 创建实例,参数为原型对象和属性描述符集 |
| 5 | 🗝️🔑 Object.defineProperty(instance💥,propName,propDescriptor) | (重新)定义属性 |
| 5 | 🗝️🔑 Object.defineProperties(instance💥,propDescriptors) | (重新)定义属性集 |
| 5 | 🗝️🔑 Object.getOwnPropertyDescriptor(instance,propName) | 查询自身的属性描述符 |
| 2017 | 🗝️🔑 Object.getOwnPropertyDescriptors(instance) | 查询自身的属性描述符集 |
| 1 | 🗝️🔑 Object.prototype.propertyIsEnumerable(propName) | 自身可枚举属性 |
原型对象及原型链条相关方法
| ecma | api | describe |
|---|---|---|
| 2015 | ⛓️ Object.getPrototypeOf(instance) | 获取实例的原型对象 |
| 2015 | ⛓️ Object.setPrototypeOf(instance💥,proto) | 设置原型对象,会破坏 JS 引擎的优化(例如 V8)导致性能不佳。 推荐 create 来创建新对象 |
| 2015 | ⛓️ Object.prototype.isPrototypeOf(instance,proto) | 判断原型对象。相当于proto === Object.prototype.getPrototypeOf(instance) |
数据结构转换
| ecma | api | describe |
|---|---|---|
| 2017 | 🗝️ Object.entries(instance) | Object转为Entries |
| 2017 | 🗝️🔑 Object.fromEntries(instance) | Entries转为Object |
| 2024 | Object.groupBy(items,callback) | 进行分组 |
属性操作
| ecma | api | describe |
|---|---|---|
| 2015 | 🔑 Object.getOwnPropertySymbols(instance) | 获取自身symbol类型的键名数组 不可枚举属性也会返回 |
| 5 | 🗝️ Object.getOwnPropertyNames(instance) | 获取自身 String类型的键名数组 不可枚举属性也返回 |
| 2015 | 🗝️🔑 Object.hasOwn(instance,propName) | 判断自身属性中有无该属性键名 |
| 3 | instance,propName) | 已废除,推荐Object.hasOwn |
| 2015 | 🗝️🔑 Object.assign(instance💥, ...sources) | 分配属性给实例。 sources列表自右向左逐个读取,然后覆盖实例上原有的属性。 source的属性是自有的、可枚举的,也可以是 null或undefined |
| 2017 | 🗝️ Object.keys(instance) | 返回键名数组 |
| 2017 | 🗝️ Object.values(instance) | 返回键值数组 |
| ecma | api | describe |
|---|---|---|
| 2015 | Object.is(value1,value2) | “同值相等”(SameValue)判断 见SameValue |
| 1 | Object.prototype.toLocaleString() | 对象的本地化字符串表示 参考国际化 |
| 1 | Object.prototype.toString() | 对象的字符串表示。内部属性值[[Class]]用于描述一个值的类型[object 类型]。用法: Object.prototype.toString.call(any).slice(8,-1) // type |
| 1 | Object.prototype.valueOf() | 取基本类型值 |