一行代码解决深拷贝问题,JavaScript新特性解析
深拷贝是JavaScript里一个常见而又棘手的问题,长久以来,我们不得不依赖各种自定义方法或第三方库来解决这一问题。大多数人都会使用JSON.parse(JSON.stringify(obj))这种方式,但它存在众多限制。好消息是,现代JavaScript为我们带来了原生的解决方案:structuredClone()方法。
深拷贝的传统解决方案及其问题
回顾一下,我们通常使用以下方法来实现深拷贝:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const deepCopy = JsON.parse(JsoN.stringify(original0bject));
function deepclone(obj){ if(obj === null||typeof obj !=='object') return obj; const copy = Array.isArray(obj) ? [] : {}; for(const key in obj){ if(object.prototype.has0wnProperty.call(obj,key)){ copy[key]= deepclone(obj[key]); } } return copy; }
const deepCopy = _.cloneDeep(original0bject);
|
这些方法各有缺点:
- JSON方法的局限性: 无法处理函数/Symbol类型/undefined值/循环引用,无法正确处理Date、RegExp、Map、Set等特殊对象,会丢失原型链
- 自定义递归函数: 实现复杂,容易出错,通常需要额外处理各种特殊类型,性能不一定理想
- 第三方库: 增加项目依赖,增加打包体积
structuredClone:现代JavaScript的深拷贝解决方案
2022年,WHATWG HTML标准引入了structuredClone()方法,现在它已被所有主流浏览器和Node.js支持。这个方法提供了一种高效、标准化的方式来创建复杂JavaScript对象的深拷贝。
基本用法
使用structuredClone()非常简单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const original={ name: 'John', age: 30, address:{ city: 'New York', country:'USA' }, hobbies: ['reading','swimming'] } const clone =structuredclone(original);
clone.address.city='Boston'; console.log(original.address.city); console.log(clone.address.city);
|
就是这么简单!一行代码,无需任何额外的库或复杂的递归函数。
structuredClone的优势
- 内置于JavaScript引擎,无需外部依赖
- 处理循环引用,不会像JSON方法那样抛出错误
- 正确处理大多数JavaScript内置类型,包括: Date对象/RegExp对象/Map和Set/ArrayBuffer和TypedArrays/Blob对象/File对象/ImageData对象/嵌套的复杂对象结构
处理循环引用的示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const original={ name: 'FedJavaScript' }; original.self = original;
try { const failed = JsoN.parse(JsoN.stringify(original)); } catch(error){ console.error('JS0N方法失败:',error.message); }
const clone=structuredclone(original); console.log(clone.name); console.log(clone.self === clone);
|
支持的数据类型详解
structuredClone()支持的类型远超JSON方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| const original = { string: 'Hello', number: 123, boolean: true, null: null, undefined: undefined,
date: newDate('2023-06-15'),
regex: /pattern/g,
map: newMap([['key', 'value']]), set: newSet([1, 2, 3]),
arrayBuffer: newUint8Array([1, 2, 3]).buffer, typedArray: newUint8Array([1, 2, 3]),
array: [1, 2, { nested: true }], object: { nested: { deep: true } } };
const clone = structuredClone(original);
console.log(clone.date instanceof Date); console.log(clone.regex instanceof RegExp); console.log(clone.map instanceof Map); console.log(clone.set instanceof Set); console.log(clone.arrayBuffer instanceof ArrayBuffer); console.log(clone.typedArray instanceof Uint8Array);
|
structuredClone的局限性
虽然structuredClone()解决了大多数深拷贝问题,但它仍有一些限制:
- 不支持函数:与JSON方法一样,函数不会被克隆
- 不克隆原型链:克隆的对象会丢失原始对象的原型链
- 不支持DOM节点
- 不支持Error对象
structuredClone() 是JavaScript生态系统中的一个重要进步,它为常见的深拷贝问题提供了一个简单、高效且标准化的解决方案。虽然它有一些限制,但在大多数常见场景中,它都是深拷贝的最佳选择。目前,structuredClone() 已被所有主流浏览器支持。