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

更新日期: 2020-10-26阅读: 1.6k标签: 拷贝

大部分情况我们都可以使用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


链接: https://fly63.com/article/detial/9981

js中深拷贝和浅拷贝的区别及原理

javascript的深拷贝和浅拷贝主要是针对像Object, Array这样的复杂对象的,简单理解为浅拷贝只复制一层对象的属性,而深拷贝则递归复制了所有层级。

使用JSON.parse(),JSON.stringify()实现对对象的深拷贝

JSON.parse(),JSON.stringify()实现对对象的深拷贝以及兼容性问题,根据不包含引用对象的普通数组深拷贝得到启发,不拷贝引用对象,拷贝一个字符串会新辟一个新的存储地址,这样就切断了引用对象的指针联系。

使用jquery克隆对象_实现深、浅拷贝的简单实例

克隆JavaScript对象,首页想到的是obj = eval(uneval(obj)),但这是非标准的,推荐使用jquery提供的jQuery.extend方法,因为它包含了一些额外的类型验证逻辑,并且不会复制未定义的属性等。

JS中如何进行对象的深拷贝

在JS中,一般的=号传递的都是对象/数组的引用,并没有真正地拷贝一个对象,那如何进行对象的深度拷贝呢?对象的深拷贝与浅拷贝的区别如下:浅拷贝:仅仅复制对象的引用,而不是对象本身;深拷贝:把复制的对象所引用的全部对象都复制一遍。

javascript实现数组或对象的深拷贝

可以看出来,改变原数组arr,并没有对新数组copyArr产生影响;改变新数组copyArr也没有对原数组arr产生影响;同样:改变原数组arr,并没有对新数组copyArr产生影响;改变新数组copyArr也没有对原数组arr产生影响;

关于内存拷贝(浅拷贝)和js链表的小知识点

记录一个做leetcode看答案学到的小知识。。。浅拷贝实现一些特殊的功能的一些应用场景,比如:我们有一个需求如下

js的浅拷贝 VS 深拷贝

我们常常会用到拷贝对象的功能,而拷贝有浅拷贝和深拷贝2种。这篇文章会着重讲2个方面:1: 浅拷贝和深拷贝的区别2: 浅拷贝和深拷贝的具体实现,拷贝我们常常用在把A对象的属性copy到B对象,这样B对象就拥有了A对象的属性。

理解JS中的深拷贝与浅拷贝

了解深拷贝也不仅仅是为了应付面试题,在实际开发中也是非常有用的。例如后台返回了一堆数据,你需要对这堆数据做操作,但多人开发情况下,你是没办法明确这堆数据是否有其它功能也需要使用,直接修改可能会造成隐性问题

Js实现深浅复制

JavaScript中有两种数据类型,基本数据类型如undefined、null、boolean、number、string,另一类是Object。简单数据类型只存储在内存中的栈区,复制的时候是值传递给新的索引。而复杂数据类型由栈区和堆区共同储存

14个JS数组拷贝技巧

数组拷贝经常被误解,但这并不是因为拷贝过程本身,而是因为缺乏对 JS 如何处理数组及其元素的理解。JS 中的数组是可变的,这说明在创建数组之后还可以修改数组的内容。这意味着要拷贝一个数组,咱们不能简单地将旧数组分配给一个新变量

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!