小tips:使用JSON.parse(JSON.stringify(object))实现深拷贝的局限及扩展

  • A+
所属分类:Web前端
摘要

大部分情况我们都可以使用JSON.parse(JSON.stringify(object))来实现深拷贝,但该方法也有局限性,如下:


使用JSON.parse(JSON.stringify(object))实现深拷贝局限

大部分情况我们都可以使用JSON.parse(JSON.stringify(object))来实现深拷贝,但该方法也有局限性,如下:

  • 会忽略 undefined
  • 会忽略 symbol
  • 不能序列化函数
  • 不能解决循环引用的对象

例如:

let a = {   age: undefined,   sex: Symbol('male'),   jobs: function() {},   name: 'yck' } let b = JSON.parse(JSON.stringify(a)) console.log(b) // {name: "yck"}

 借用 MessageChannel 实现深拷贝

MessageChannel API允许我们创建一个新的消息通道,并通过它的两个MessagePort属性发送数据。

var channel = new MessageChannel();

这样就创建了一个管道。

实例属性:

channel.port1 channel.port2

获取实例的两个端口,注意的是,两个端口都是只读的。

简单来说,MessageChannel创建了一个通信的管道,这个管道有两个端口,每个端口都可以通过postMessage发送数据,而一个端口只要绑定了onmessage回调方法,就可以接收从另一个端口传过来的数据。

一个简单的例子:

var channel = new MessageChannel(); var port1 = channel.port1; var port2 = channel.port2; port1.onmessage = function(event) {     console.log("port1收到来自port2的数据:" + event.data); } port2.onmessage = function(event) {     console.log("port2收到来自port1的数据:" + event.data); }  port1.postMessage("发送给port2"); port2.postMessage("发送给port1");

而通过 postMessage() 方法传输的 message 参数是深拷贝的。

function deepClone(val) {     return new Promise((resolve,reject) => {         const {port1,port2} = new MessageChannel();         port2.onmessage = e => resolve(e.data);         port1.postMessage(val);     }) }  let obj = {   age: undefined,   name: 'yck',   c: {       d: true   } } obj.c.e = obj.c; // 循环引用  // 注意该方法是异步 async function test() {     const clone = await deepClone(obj);     console.log(clone) // {age: undefined, name: "yck", c: {…}} } test()

但这个深拷贝只能解决 undefined 和循环引用对象的问题,对于 Symbol 和 function 依然束手无策。

详细可参考:《MessageChannel 消息通道》

简易版的深拷贝

var extendCopy = (function f(p,c){     var c = c || {};     for (var i in p) {         if(typeof p[i] === 'object'){             c[i] = (p[i] instanceof Array) ? [] : {};             f(p[i],c[i]);         }else{              c[i] = p[i];         }      }     return c; });

详细可参考:《小tips:JS之浅拷贝与深拷贝》

lodash 的深拷贝函数

语法:

_.cloneDeep(value)

示例:

var objects = [{ 'a': 1 }, { 'b': 2 }];   var deep = _.cloneDeep(objects); console.log(deep[0] === objects[0]); // => false

地址:https://lodash.com/docs/4.17.15#cloneDeep