前言

像map、filter、some等方法都是Object实例的方法,即原型链方法。
Object的静态方法不依赖于任何对象实例,而是直接调用Object类本身。

常用静态方法如下:

一、Object.assign(target,…source)

将一个或多个源对象的属性复制到目标对象,并返回目标对象
如果有相同属性,会根据参数顺序依次覆盖对应的值。

const target = { a: 1, b: 2 };
const source1 = { b: 3, c: 4 };
const source2 = { b: 5, c: 6, d: 7 };
const merged = Object.assign(target, source1, source2);

console.log(merged); // {a: 1, b: 5, c: 6, d: 7}

真实场景

vue3的reactive数据替换整个对象,注意:ref数据不需要,Obj.value = newObj 即可。

二、Object.keys(obj)

返回一个数组,其中包含对象的所有可枚举属性的名称。

const obj = { a: 1, b: 2, c: 3 };
const keys = Object.keys(obj);

console.log(keys); // ["a", "b", "c"]

三、Object.getOwnPropertyNames(obj)

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

const obj = { a: 1, b: 2, c: 3 };
console.log(Object.getOwnPropertyNames(obj)); // ["a", "b", "c"]

二三对比

上面两种方法均可获取对象的所有属性,但是有什么区别呢

返回结果

Object.getOwnPropertyNames(obj): 返回一个包含对象自身的所有属性名称「包括不可枚举属性」的数组。
Object.keys(obj): 返回一个包含对象自身的「所有可枚举属性」的数组。

const obj = {
  a: 1,
  b: 2,
};

// 添加一个不可枚举属性 c
Object.defineProperty(obj, 'c', {
  value: 3,
  enumerable: false,
});

console.log(Object.getOwnPropertyNames(obj)); // ["a", "b", "c"]
console.log(Object.keys(obj)); // ["a", "b"]

包含属性的顺序

Object.getOwnPropertyNames(obj) 返回的属性名称数组中的元素顺序是从对象属性添加的顺序到被删除的顺序。
Object.keys(obj) 返回的属性名称数组中的元素顺序可能与属性添加到对象中的顺序不同,因为它只返回对象的可枚举属性名称。

四、Object.values(obj)

返回一个数组,其中包含对象的所有可枚举属性的值。

const obj = { a: 1, b: 2, c: 3 };
const values = Object.values(obj);

console.log(values); // [1, 2, 3]

五、Object.defineProperty(obj, prop, descriptor)

在对象上定义一个新属性或修改现有属性的特性。

Object.defineProperty(obj, 'prop', {
  value: 'value',
  writable: true,
  enumerable: true,
  configurable: true
});

Vue2中对其的应用

Vue2 通过Object.defineProperty来劫持对象的属性,使得当属性被访问或者修改时,可以执行相应的操作,比如更新视图。Vue3中ref的基本类型数据也采用的Object.defineProperty,但是ref的复杂数据类型的底层实现与reactive一致。

数据响应式

Vue.js利用Object.defineProperty在对象上定义属性的getter和setter来实现数据的响应式。当数据发生变化时,能够自动更新相关的视图。

let data = { value: '张三' };

Object.defineProperty(data, 'value', {
  get() {
    console.log('Get');
    return this._value;
  },
  set(newValue) {
    console.log('Set');
    this._value = newValue;
  }
});

console.log(data.value); // 张三
data.value = '李四'; // 触发set('李四')
console.log(data.value); // 李四

访问控制

通过Object.defineProperty可以限制属性的访问权限,比如设置属性为「只读」或者「不可枚举」。

let obj = {};

Object.defineProperty(obj, 'readOnly', {
  value: '张三',
  writable: false, // 设置为只读
  enumerable: true // 可枚举
});

console.log(obj.readOnly); // 张三
obj.readOnly = '李四'; // 不会改变值,不会报错,但是无效

属性扩展

可以利用Object.defineProperty来添加一些特殊的属性,比如计算属性。

let obj = { firstName: '张', lastName: '三' };

Object.defineProperty(obj, 'fullName', {
  get() {
    return this.firstName + ' ' + this.lastName;
  },
  set(value) {
    const parts = value.split(' ');
    this.firstName = parts[0];
    this.lastName = parts[1];
  }
});

console.log(obj.fullName); // 张 三
obj.fullName = '李 四';
console.log(obj.firstName); // 李
console.log(obj.lastName); // 四

六、Object.defineProperties(obj, props)

在对象上定义一个或多个新属性或修改现有属性的特性。

Object.defineProperties(obj, {
  prop1: { value: 'value1', writable: true },
  prop2: { value: 'value2', writable: true }
});

七、Object.entries(obj)

返回一个包含对象的所有可枚举属性的键值对数组。

const obj = { a: 1, b: 2, c: 3 };
const entries = Object.entries(obj);

console.log(entries); // [["a", 1], ["b", 2], ["c", 3]]

八、Object.fromEntries(iterable)

将一个键值对的列表转换为一个对象。

const entries = [['a', 1], ['b', 2]];
console.log(Object.fromEntries(entries)); // { a: 1, b: 2 }

九、Object.freeze(obj)

冻结一个对象,防止对其进行修改,不可修改值或添加新属性。
即使修改不报错,但也未生效。

const obj = { a: 1, b: 2 };
Object.freeze(obj);
obj.a = 10; // 不会生效
obj.c = 10; // 不会生效
console.log(obj); // { a: 1, b: 2 }

十、Object.isFrozen(obj)

返回一个布尔值,判断一个对象是否被冻结。

const obj = { a: 1 };
Object.freeze(obj);
console.log(Object.isFrozen(obj)); // true

十一、Object.seal(obj)

封闭一个对象,防止添加新属性和删除现有属性,但允许修改现有属性的值。

const obj = { a: 1, b: 2 };
Object.seal(obj);
obj.a = 10; // 可以修改
obj.c = 3; // 不会生效
console.log(obj); // { a: 10, b: 2 }

十二、Object.isSealed(obj)

返回一个布尔值,判断一个对象是否被封闭。

const obj = { a: 1 };
Object.seal(obj);
console.log(Object.isSealed(obj)); // true
03-14 04:14