深拷贝与浅拷贝

66 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天

javascript中数据类型分为基本数据类型和引用数据类型,复制基本数据类型会在栈中开辟新的空间,将变量指向新值,新旧变量互不影响。复制引用数据类型时候,也是在栈中开辟新的空间,这个栈中存的是地址,新旧地址指向堆中的同一个实体,两者会相互影响。

浅拷贝:拷贝的对象指针,不复制对象本身,新旧对象共享同一块内存,互相影响。 深拷贝:拷贝对象本身,开辟新地址,新旧对象不共享,互不影响。 拷贝数组只有一层时候是深拷贝

一、浅拷贝

创建一个新的对象,遍历需要克隆的对象,将需要克隆对象的属性依次添加到新对象上,返回。

let source = {a:1}
function clone(source){
let target = {};
for(let i in source){
 if(source.hasOwnProperty(i)){
 target[i]=source[i]
 }
}
return target
}
let target = clone(source)

Object.assign({},source)

var _ = require('lodash'); var target = _.clone(source);

let target= {... source}

let target = source.concat();

let target = source.slice();

当原数据Array只有一层的时候,是深拷贝;所以当原数据进行浅拷贝,改变arr2的arr[1],而原数据arr1中的arr1[1]没有改变;

二、深拷贝

let target = JSON.parse(JSON.stringify(source));

利用JSON.stringify将对象转成JSON字符串,再用JSON.parse把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。这种方法虽然可以实现数组或对象深拷贝,但不能处理函数和正则,因为这两者基于JSON.stringify和JSON.parse处理后,得到的正则就不再是正则(变为空对象),得到的函数就不再是函数(变为null)了

var _ = require('lodash'); var target = _.cloneDeep(source);

V 1.0

原始类型直接返回、引用类型创建新对象,递归至基本数据类型为止、考虑数组情况

function clone(target) 
{
    if (typeof target === 'object') 
    { 
        let cloneTarget = Array.isArray(target) ? [] : {}; 
        for (const key in target) 
        { 
        cloneTarget[key] = clone(target[key]); 
        } 
        return cloneTarget; 
    } 
    else 
    { 
        return target; 
    } 
};

V 2.0循环引用

V 3.0考虑其他数据类型

三、=、浅拷贝、深拷贝区别

针对引用数据类型

赋值:拷贝的是栈中的地址,不是堆中的数据,新旧地址指向同一个存储空间,不管是基本类型还是引用类型都互相影响。

// 对象赋值 
let obj1 = { name : 'js', arr : [1,[2,3],4], }; 
let obj2 = obj1; 
obj2.name = "node"; obj2.arr[1] =[5,6,7] ; 
console.log('obj1',obj1) // obj1 { name: 'node', arr: [ 1, [ 5, 6, 7 ], 4 ] } console.log('obj2',obj2) // obj2 { name: 'node', arr: [ 1, [ 5, 6, 7 ], 4 ] }

浅拷贝:在堆中创建新内存,拷贝前后若是基本类型互不影响,若是引用类型因共享同一块内存,会相互影响。

// 浅拷贝:name互不影响,arr相互影响
let obj1 = {
    name: 'js',
    arr: [1, [2, 3], 4],
};
let obj3 = shallowClone(obj1)
obj3.name = "node";
obj3.arr[1] = [5, 6, 7]; // 新旧对象共享同一块内存
// 这是个浅拷贝的方法
function shallowClone(source) {
    var target = {};
    for (var i in source) {
        if (source.hasOwnProperty(i)) {
            target[i] = source[i];
        }
    }
    return target;
}
console.log('obj1', obj1) 
console.log('obj3', obj3)

深拷贝:从堆内存中创建新内存存放新对象,对对象中的子对象进行递归拷贝,互不影响。

// 深拷贝 
let obj1 = { name : '浪里行舟', arr : [1,[2,3],4], }; 
let obj4=deepClone(obj1) obj4.name = "阿浪"; obj4.arr[1] = [5,6,7] ; // 新对象跟原对象不共享内存 // 这是个深拷贝的方法 
function deepClone(obj) 
{ 
if (obj === null) return obj; 
if (obj instanceof Date) return new Date(obj); 
if (obj instanceof RegExp) return new RegExp(obj); 
if (typeof obj !== "object") return obj; 
let cloneObj = new obj.constructor(); 
for (let key in obj) 
{ 
if (obj.hasOwnProperty(key)) 
{ 
 // 实现一个递归拷贝 
 cloneObj[key] = deepClone(obj[key]); 
} } 
return cloneObj; 
} 
console.log('obj1',obj1) // obj1 { name: '浪里行舟', arr: [ 1, [ 2, 3 ], 4 ] } console.log('obj4',obj4) // obj4 { name: '阿浪', arr: [ 1, [ 5, 6, 7 ], 4 ] }

总结:

基本数据类型:赋值互相影响,浅拷贝深拷贝不影响

引用数据类型,赋值 浅拷贝互相影响,深拷贝不影响