在 JavaScript 开发中,对象深拷贝(对象拷贝到新的内存地址)是一个常见的需求。在 ES7 之前,我们通常使用 stringify 和 parse 方法实现对象深拷贝,这种方法的缺陷是无法拷贝对象的非枚举属性。ES7 中新增了一个方法 Object.getOwnPropertyDescriptors 可以完美地解决这个问题。
Object.getOwnPropertyDescriptors 方法
Object.getOwnPropertyDescriptors 方法返回指定对象所有自身属性(非继承属性)的描述对象,这里的描述对象指的是 Object.prototype.propertyIsEnumerable 方法返回 false 的对象,即不能枚举的对象。描述对象的格式如下:
{ configurable: true, // 描述对象是否可被删除等 enumerable: true, // 描述对象是否可被 for...in 遍历 value: 'xxx', // 描述对象的值 writable: true // 描述对象是否可被修改 }
下面是一个使用 Object.getOwnPropertyDescriptors 方法获取对象属性描述的示例代码:
const obj = { name: '小明', age: 18 } console.log(Object.getOwnPropertyDescriptors(obj))
运行结果如下:
{ age: { value: 18, writable: true, enumerable: true, configurable: true }, name: { value: '小明', writable: true, enumerable: true, configurable: true } }
可以看到,Object.getOwnPropertyDescriptors 方法返回的是一个对象,对象的每个属性都是该对象的一个属性描述原型(property descriptor)。每个属性描述原型值包含属性值及其配置。其中,属性描述原型的 key 和 value 分别是对象原型的属性名和属性值。
对象深拷贝的实现
有了 Object.getOwnPropertyDescriptors 方法,我们就可以实现深拷贝了。下面是一个简单的深拷贝代码示例:
-- -------------------- ---- ------- -------- -------------- - ----- -------- - ----------------------------------------- -------------------------------------------- -- - ----- ------------------ - ------------------------------------ ----- ------------------------------- ----- - ---------------------- ------ ----------------------------------- -- -- ------ -------- - ----- --- - - ----- ----- ---- --- ------ - ----- ---------- ----- -------- - - ----- -------- - -------------- --------------------- --------------- --- --------- --------------------- --- ---------------
运行结果如下:
{ name: '小明', age: 18, skill: { code: 'program', tool: 'vscode' } } false false
从运行结果可以看出,原始对象和克隆对象互不影响,可以完整地拷贝对象的属性,包括非枚举属性。
注意事项
当使用 Object.getOwnPropertyDescriptors 方法时,需要注意以下几点:
Object.getOwnPropertyDescriptors 方法不会枚举原型链上的属性,只会返回本身的属性描述对象。
Object.getOwnPropertyDescriptors 方法返回的属性描述对象不包含 get 和 set 方法。
使用 Object.getOwnPropertyDescriptors 方法进行拷贝时,需要注意原始对象中是否引用了自身,如果存在,则可能会导致死循环。
总结
ES7 中的 Object.getOwnPropertyDescriptors 方法是处理对象深度复制的良好方式。使用该方法可以完整地拷贝对象的属性,包括非枚举属性。同时,需要注意其局限性,比如不会枚举原型链上的属性,返回对象描述对象不包含 get 和 set 方法,以及可能会导致死循环等一些问题。因此,在使用时需要根据实际情况进行处理。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64df9955f6b2d6eab3acdbbc