美文网首页纵横研究院前端基础技术专题社区
JavaScripts数据的深拷贝和浅拷贝

JavaScripts数据的深拷贝和浅拷贝

作者: a095 | 来源:发表于2020-07-12 20:39 被阅读0次
// 对象和数组都属于引用类型,直接赋值是他们会指向同一个对象/数组,对于引用类型的数据只复制引用,没有复制真正的值。
var obj1 = { name: 'yc' }
var obj2 = obj1;
obj2.name = 'zl';
console.log(obj1, obj2); // { name: 'zl' } { name: 'zl' }

var arr1 = [1, 2, 3, 4]
var arr2 = arr1;
arr2.push(5);
console.log(arr1, arr2); // [1, 2, 3, 4, 5] [1, 2, 3, 4, 5]
几种浅拷贝的实现方式
es6扩展运算符「...」
let a = { name: 2, val: 3 };
let b = { ...a };
b.name = 3;
console.log(a, b); // { name: 2, val: 3 } { name: 3, val: 3 }
Object.assign()
let a = { name: 2, value: 3 };
let b = Object.assign([], a);
b.name = 3;
console.log(a, b);
数组中的slice() & concat()
let arr = [1, 2, 3, 4, 5];
let arr2 = arr.concat();
let arr3 = arr.slice();
arr2[2] = 6;
arr3[3] = 0;
console.log(arr2, arr3); // [ 1, 2, 6, 4, 5 ] [ 1, 2, 3, 0, 5 ]

注:如果对象/数组的内部是基本数据类型,可以实现深拷贝,如果嵌套了引用类型,只有外层数据是深拷贝,深层次的数据仍然是浅拷贝。

几种深拷贝的方法
JSON方法
var arr1 = [1, 2, 3, 4]
var arr2 = JSON.parse(JSON.stringify(arr1));
arr2.push(5);
console.log(arr1, arr2); // [1, 2, 3, 4] [1, 2, 3, 4, 5]

注:简单粗暴,但是数据中存在函数等复杂的数据结构时不能使用。

// 对象中出现函数时,不能使用
var obj1 = {
    name: 'yc',
    show: function (ele) {
        console.log(ele);
    }
}
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.name = 'zl';
console.log(obj1, obj2); // { name: 'yc', show: [Function: show] } { name: 'zl' }
// 像Maps, Sets, RegExps, Dates, ArrayBuffers和其他内置对象序列化可能存在问题
// 比如Date序列化后再反序列化回来就变成字符串了,而不是Date对象。
let a = new Date();
let b = JSON.stringify(a);
let c = JSON.parse(b); // c应该被转化成Date对象 但实际上JSON.parse()的结果是字符串
console.log(typeof a, a); // object 2020-05-27T05:56:21.561Z
console.log(typeof c, c); // string 2020-05-27T05:56:21.561Z
// 无法处理循环问题
const x = {};
const y = {x};
x.y = y; // { y: { x: [Circular] } }
JSON.stringify(x); // Converting circular structure to JSON
自定义deepClone函数实现深拷贝

实际上,如果了解数据具体的结构,可以通过for循环遍历数据的所有属性,逐个赋值给新对象,已有许多javascript库实现了深拷贝的方法。

function deepClone(obj) {
    function isObject(o) {
        return (typeof o === 'object' || typeof o === 'function') && o !== null
    }
    if (!isObject(obj)) {
        throw new Error('非对象')
    }
    let isArray = Array.isArray(obj);
    let newObj = isArray ? [...obj] : { ...obj };
    // for (let key in obj)
    Reflect.ownKeys(obj).forEach(
        (key) => {
            newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key];
        }
    )
    return newObj;
}

let a = { name: 1, value: { wto: true } };
let b = deepClone(a);
b.value.wto = 2;
console.log(a, b); // { name: 1, value: { wto: true } } { name: 1, value: { wto: 2 } }

注:通用的解决方案,Circular等数据类型时仍然存在问题。

Circular的深拷贝问题
function deepClone(obj, hash = new Map()) {
    if (typeof obj !== 'object') return obj;
    if (hash.get(obj)) {
        return hash.get(obj);
    }
    let newObj = new obj.constructor; // 新建newObj空对象
    // 讲对象的引用保存在Map对象中 拷贝时检测到重复对象时不再重复拷贝 而是使用Map中已有的对象
    hash.set(obj, newObj);
    for (let key in obj) {
        newObj[key] = deepClone(obj[key], hash);
    }
    return newObj;
}
let obj = { a: 1 };
obj.b = obj;
let res = deepClone(obj);
res.b = 2;
console.log(res, obj); // { a: 1, b: 2 } { a: 1, b: [Circular] }

注:对于函数,正则等复杂对象的深拷贝,同样可以通过判断数据类型,新建相应对象的方式进行深拷贝。实际上,遇到Circular等复杂对象的深拷贝问题时,应当优先考虑是否能够修改数据结构以避免深拷贝。

相关文章

  • JavaScripts数据的深拷贝和浅拷贝

    几种浅拷贝的实现方式 es6扩展运算符「...」 Object.assign() 数组中的slice() & co...

  • Java基础 - 深拷贝和浅拷贝

    Java 的深拷贝和浅拷贝 什么是深拷贝、浅拷贝 (深克隆、浅克隆)? 在 Java 中,数据类型分为 基本数据类...

  • js浅拷贝深拷贝

    js浅拷贝,深拷贝的简单实现 基础数据 浅拷贝 深拷贝

  • iOS深拷贝(MutableCopy)与浅拷贝(Copy)的区别

    深拷贝和浅拷贝的概念 iOS中有深拷贝和浅拷贝的概念,那么何为深拷贝何为浅拷贝呢?浅拷贝:浅拷贝并不拷贝对象本身,...

  • Java深拷贝和浅拷贝的区别

    一、深拷贝和浅拷贝的区别 浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。 深拷...

  • js深拷贝浅拷贝

    目录 一.数据类型 二.浅拷贝与深拷贝 三.赋值和浅拷贝的区别 四.浅拷贝的实现方式 五.深拷贝的实现方式 一.数...

  • 实现一个深拷贝

    深拷贝和浅拷贝是针对复杂数据类型来说的,浅拷贝只拷贝一层,而深拷贝是层层拷贝。 代码中理解...

  • 深拷贝、浅拷贝

    深拷贝和浅拷贝只针对引用数据类型,比如Object和Array深拷贝:从A拷贝到B,当A发生改变时B不会变;浅拷贝...

  • 关于Java的浅拷贝和深拷贝

    浅拷贝和深拷贝是什么? 浅拷贝和深拷贝都是针对已经存在了的对象的操作,在java中,基本数据类型有八种,和引用数据...

  • iOS面试题-第二页

    11.深拷贝和浅拷贝的理解. 深拷贝;拷贝的内容. 浅拷贝:拷贝的指针. 深拷贝如: NSMutableDicti...

网友评论

    本文标题:JavaScripts数据的深拷贝和浅拷贝

    本文链接:https://www.haomeiwen.com/subject/hrencktx.html