深拷贝与浅拷贝的实现

127 阅读1分钟

1. 浅拷贝的实现

1.1引用赋值(首层深)

function shallowClone(source) {
    var target = {};
    for(var i in source) {
        if (source.hasOwnProperty(i)) {
            target[i] = source[i];
        }
    }
    return target;
}

1.2 Object.assign()

var x = {
  a: 1,
  b: { f: { g: 1 } },
  c: [ 1, 2, 3 ]
};
var y = Object.assign({}, x);
console.log(y.b.f === x.b.f);     // true

2. 深拷贝的实现

2.1 JSON的parse和stringify

JSON.stringify 是将一个 JavaScript 值转成一个 JSON 字符串。

JSON.parse 是将一个 JSON 字符串转成一个 JavaScript 值或对象。

我们可以通过上述两种转换的结合来进行深拷贝

const originArray = [1,2,3,4,5];
const cloneArray = JSON.parse(JSON.stringify(originArray));
console.log(cloneArray === originArray); // false

const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
const cloneObj = JSON.parse(JSON.stringify(originObj));
console.log(cloneObj === originObj); // false

cloneObj.a = 'aa';
cloneObj.c = [1,1,1];
cloneObj.d.dd = 'doubled';

console.log(cloneObj); // {a:'aa',b:'b',c:[1,1,1],d:{dd:'doubled'}};
console.log(originObj); // {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};

不过这只能适用于一些简单的情况,比如对象中带有方法就不行,因为undefinedfunctionSymbol会在转换过程中被忽略。

2.2 递归

function deepClone(source) {
        const target = source.constructor === Array?[]:{}
        for (const key in source) {
            if (source.hasOwnProperty(key)) {
                // 如果是对象就递归,不是就直接赋值
                if (source[key] && typeof source[key] === 'object') {
                    target[key] = source[key].constructor === Array ? [] : {}
                    target[key] = deepClone(source[key])
                } else {
                target[key] = source[key]
                }
            } 
        }
        return target
    }
    const originObj = {a:'a',b:'b',c:[1,2,3],d:{dd:'dd'}};
    const cloneObj = deepClone(originObj)
    console.log(cloneObj === originObj); // false

2.3 contact和slice

contact是连接两个或多个数组的方法,我们通过实例可以发现它是一个首层深拷贝的方法。

const originArray = [1,[1,2,3],{a:1}];
const cloneArray = originArray.concat();
console.log(cloneArray === originArray); // false
cloneArray[1].push(4);
cloneArray[2].a = 2; 
console.log(originArray); // [1,[1,2,3,4],{a:2}]

经过测试,slice同样也是首层深拷贝。