prefácio
Quando se trata de cópia profunda de JS, dois métodos de implementação podem aparecer automaticamente em sua mente:
-
JSON.parse(JSON.stringify(obj))
-
clone de lodashDeep
Ambos os dois métodos de cópia profunda acima têm algumas desvantagens (que serão descritas em detalhes posteriormente neste artigo); portanto, ao aprender os métodos de cópia profunda acima, você pode ter pensado por que o navegador não suporta cópia profunda nativa? Isso não é estruturadoClone aqui~ A API de cópia profunda suportada nativamente pelo tempo de execução do navegador
Desvantagens de JSON.parse(JSON.stringify(obj))
-
Se o seu objeto obj tiver uma referência circular, esse método relatará um erro
-
Se seu objeto obj tiver um objeto Date, este método irá convertê-lo em uma string
-
Se houver objetos Set, Map, Regular, Error em seu objeto obj, este método irá convertê-los em objetos literais vazios { }, se houver indefinido, este método irá ignorar diretamente
Veja os resultados da execução na figura acima, os objetos de Set, Map, Regular e Error se tornaram { } e undefined desapareceu. . .
Possíveis riscos de Lodash
O tree-shaking de Lodash pode ser diferente do nosso pensamento.Se o andaime do seu projeto não lidar com esse problema e você não prestar atenção na maneira como ele é introduzido, isso causará alguma perda de desempenho.
Para lidar com o tremor de árvore de lodash, consulte:
Importar lodash sob demanda - One Leaf One Bodhi 22 - 博客园
Existem certos problemas nos dois métodos comuns de cópia profunda* (mas eles também têm suas próprias vantagens. Os leitores devem escolher o método apropriado de cópia profunda com base em sua própria compreensão de cópia profunda e o uso da cena. Este artigo irá comparar brevemente os três métodos de cópia profunda no final.método)*, que leva a estruturadoClone, o protagonista deste artigo:
Introdução à sintaxe estruturadoClone
全局的 structuredClone() 方法使用结构化克隆算法将给定的值进行深拷贝。
该方法还支持把原始值中的可转移对象转移到新对象,而不是把属性引用拷贝过去。 可转移对象与原始对象分离并附加到新对象;它们不可以在原始对象中访问被访问到。
——MDN
介绍 structuredClone 方法深拷贝的基础用法
const person = {
name: "Timmy",
gradutionDate: new Date('2017-06-17'),
readingBooks: ['Dream of the Red Chamber']
}
const copied = structuredClone(person)
复制代码
在 console 控制台做个测试:
很多情况下,上述结果确实更符合我们开发者的使用心智!
structuredClone 深拷贝的能力如下:
-
Copy 无限嵌套的对象和数组
-
Copy 循环引用
-
Copy 如下数据类型:
仅支持以下 Error 类型:Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError(或其它会被设置为 Error 的)。
structuredClone 不能做什么:
-
Function 对象是不能被结构化克隆算法复制的;如果你尝试这样子去做,这会导致抛出 DATA_CLONE_ERR 的异常。
-
企图去克隆 DOM 节点同样会抛出 DATA_CLONE_ERR 异常。
-
对象的某些特定参数也不会被保留
介绍 structuredClone 方法转移[可转移对象]的用法
语法:
structuredClone(value, { transfer })
复制代码
Quando a transferência de parâmetro opcional é passada para o método estruturadoClone, o objeto transferível só pode ser transferido sem ser clonado. A transferência torna o objeto original (propriedades nele) inutilizável.
var uInt8Array = new Uint8Array(1024 * 1024 * 16); // 16MB
for (var i = 0; i < uInt8Array.length; ++i) {
uInt8Array[i] = i;
}
const transferred = structuredClone(uInt8Array, { transfer: [uInt8Array.buffer] });
console.log(uInt8Array.byteLength); // 0
复制代码
Comparando três métodos de cópia profunda
-
O método JSON.parse(JSON.stringify(obj)) é fácil de usar e tem boa compatibilidade. Se você estiver lidando com uma cópia profunda de um tipo de dados simples, esse método pode ser mantido
-
_.copyDeep tem boa compatibilidade e funções poderosas. Não irá relatar erros para os tipos Function, mas a desvantagem é que você precisa prestar atenção ao tremor da árvore, caso contrário, haverá perda de desempenho
-
O método estruturadoClone é suportado nativamente pelos navegadores e relatará um erro para o tipo Function, mas a principal desvantagem são os problemas de compatibilidade:
shim do método estruturadoClone: github.com/ungap/struc…
Documentos de referência:
[1] Objetos de clonagem profunda em JavaScript, a maneira moderna
[3] estruturadoClone() - Técnicas de desenvolvimento web | MDN
[4] Algoritmo de clonagem estruturada - Referência de interface de API da Web | MDN
[5] Objetos transferíveis - Referência da interface da API da Web | MDN