返回

浅拷贝的思考:从对象的遍历到浅拷贝的正确姿势

前端

从遍历的角度看浅拷贝

浅拷贝是指只拷贝对象的一层属性,而不会拷贝对象的嵌套属性。ES6之前,实现浅拷贝的方式很简单,只要遍历对象的所有属性,然后将属性和值拷贝到一个新的对象即可。

function shallowCopy1(obj) {
  const newObj = {};
  for (const key in obj) {
    newObj[key] = obj[key];
  }
  return newObj;
}

这种方式虽然简单,但是有个问题,那就是它只能拷贝对象的可枚举属性。不可枚举属性是指那些使用Symbol类型作为键的属性。在ES6之前,Symbol类型还没有被引入,因此这个问题并不存在。但是,在ES6之后,Symbol类型被引入,这就使得浅拷贝变得更加复杂。

深入理解属性符

为了解决这个问题,我们需要深入理解对象的属性符的概念。属性描述符是一个对象,它描述了对象的属性的各种特性,包括属性的值、是否可枚举、是否可写、是否可配置等。

我们可以使用Object.getOwnPropertyDescriptors()方法来获取对象的属性描述符。该方法返回一个对象,对象的键是属性的名称,值是属性的描述符。

const obj = {
  name: '张三',
  age: 18,
  [Symbol('salary')]: 10000
};

const descriptors = Object.getOwnPropertyDescriptors(obj);

console.log(descriptors);

输出结果:

{
  name: {
    value: '张三',
    writable: true,
    enumerable: true,
    configurable: true
  },
  age: {
    value: 18,
    writable: true,
    enumerable: true,
    configurable: true
  },
  [Symbol('salary')]: {
    value: 10000,
    writable: true,
    enumerable: false,
    configurable: true
  }
}

从输出结果可以看出,Object.getOwnPropertyDescriptors()方法返回了一个对象,对象的键是属性的名称,值是属性的描述符。属性描述符是一个对象,它描述了对象的属性的各种特性,包括属性的值、是否可枚举、是否可写、是否可配置等。

掌握Object.defineProperties()方法

既然我们已经了解了属性描述符的概念,那么我们就可以使用Object.defineProperties()方法来实现对象的浅拷贝。该方法接受两个参数,第一个参数是目标对象,第二个参数是一个对象,对象的键是属性的名称,值是属性的描述符。

function shallowCopy2(obj) {
  const newObj = {};
  const descriptors = Object.getOwnPropertyDescriptors(obj);

  Object.defineProperties(newObj, descriptors);

  return newObj;
}

这种方式可以实现对象的浅拷贝,包括可枚举属性和不可枚举属性。

揭示对象的浅拷贝的正确姿势

现在,我们已经了解了对象浅拷贝的两种方式。第一种方式比较简单,但是只能拷贝对象的可枚举属性。第二种方式比较复杂,但是可以拷贝对象的可枚举属性和不可枚举属性。

那么,哪种方式是正确的呢?

其实,两种方式都是正确的。第一种方式适用于那些只需要拷贝对象的可枚举属性的情况。第二种方式适用于那些需要拷贝对象的可枚举属性和不可枚举属性的情况。

总结

本文从遍历的角度、属性描述符的概念和Object.defineProperties()方法三个方面,逐步揭示了对象的浅拷贝的正确姿势。理解这些方法有助于提高我们对JavaScript语言的理解。