初探浅拷贝&深拷贝

2018-10-09  本文已影响121人  林键燃

思考

这个代码为什么具有深拷贝作用

obj = JSON.parse(JSON.stringify(deepCloneObj));

浅拷贝与深拷贝

在JavaScript中,对于Object和Array这类引用类型值,当从一个变量向另一个变量复制引用类型值时,这个值的副本其实是一个指针,两个变量指向同一个堆内存中的对象,改变其中一个变量,另一个也会受到影响。

这种拷贝分为两种情况:拷贝引用和拷贝实例,也就是我们说的浅拷贝和深拷贝

浅拷贝

将原对象/数组的引用直接赋给新对象/数组,新对象/数组只是原对象/数组的一个引用

深拷贝

创建一个新的对象/数组,将原对象的各项属性的“值”(数组的所有元素拷贝过来),是“值”而不是“引用”

实例1:利用 parse() 方法和 stringify() 方法实现对一个对象的深拷贝。

stringify() 方法可以将一个JS对象序列化一个JSON字符串,parse()方法可以将JSON字符串反序列化为一个JS对象。通过这两个方法可以实现对象的深拷贝。

function deepClone(obj) {
    return JSON.parse(JSON.stringify(obj))
}
const obj = {
    arr: ['a', 'n', 'd'],
    number: 1,
    obj: {
        name: 'Aranl',
        age: 18
    },
    func: function() {
        return 'ok'
    }
}
const objClone = deepClone(obj)
console.log(objClone) // => 
/*
    [object Object] {
      arr: ["a", "n", "d"],
      number: 1,
      obj: [object Object] {
        age: 18,
        name: "Aranl"
      }
    }
*/

在上面的例子中,我们可以看出,原对象的方法在拷贝的过程中丢失了,原因是在序列化JS对象的过程中,所有的函数和原型成员会被有意的忽略。

实例2:利用 parse() 方法和 stringify() 方法实现将一个或者或多个对象深拷贝到目标对象中
/**
 * 对传入一个目标对象和一个对象或多个对象进行深拷贝操作,若属性相同,则取用后面对象的值
 * 返回深拷贝操作后的对象
 * @param { Object } target
 * @param 一个或多个 { Object } sources
 * @return { Object } target
 */
function deepCloneObjects(target, ...sources) {
 sources.forEach(src=>{
   for(let key in src) {
     if(typeof src[key] === 'object') {
       target[key] = JSON.parse(JSON.stringify(src[key]))
     }else {
       target[key] = src[key]
     }
   }
 })
 return target
}
实例3: 通过递归的方式,实现对一个对象进行深拷贝
    /**
     * 使用for in拷贝对象、数组 可拷贝方法
     * @param {object} obj 拷贝模式
     * @returns {array, object} 返回拷贝后的数组、对象
     */
    function deepClone(obj) {
        let temp = Array.isArray(obj) ? [] : {}
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
                if (obj[key] && typeof obj[key] === 'object') {
                    temp[key] = deepClone(obj[key])
                } else {
                    temp[key] = obj[key]
                }
            }
        }
        return temp
    }
    
    let obj = [1,2,{m:1}]
    let deepCloneObj = deepClone(obj)
    deepCloneObj.push(3)
    console.log(obj, deepCloneObj)
实例4: 通过递归的方式,实现对一个或者多个对象深拷贝
/**
 * 对传入一个对象进行深拷贝操作,多个对象进行深拷贝“merge”操作
 * 返回深拷贝“merge”操作后的对象
 *
 * @param 一个或多个 { Object } obj
 * @return { Object } obj
 */
 
function mergeObj() {
    const _copy = (obj1,obj2) => {
        const _obj = Object.assign({}, obj1);
        for (const key in obj2) {
            const type1 = toString.call(_obj[key])
            const type2 = toString.call(obj2[key])
            if (type1 === type2 && type2 === '[object Array]') {
                _obj[key] = _obj[key].concat(obj2[key])
            } else if (type1 === type2 && type2 === '[object object]') {
                _obj[key] = _copy(_obj[key], obj2[key])
            } else {
                _obj[key] = obj2[key]
            }
        }
        return _obj
    }
    
    const _args = Object.assign({}, arguments)
    let _len = Object.keys(_args).length
    while (_len-- > 0) {
        _args[_len - 1] = _copy(_args[_len - 1], _args[_len]);
    }
    return _args[0]
}

参考链接

JavaScript中的浅拷贝和深拷贝
详解JavaScript的深拷贝
深拷贝与浅拷贝的区别,实现深拷贝的几种方法

上一篇 下一篇

猜你喜欢

热点阅读