JavaScript中的浅拷贝和深拷贝?他们的区别是什么?

在了解浅拷贝和深拷贝前,需要先了解到JavaScript中的不同数据存储方式,不同数据类型的拷贝方式,也是不同的。

基本类型数据和引用数据类型

基本数据类型
String Number Boolean Null Undefined
引用数据类型
Object
JS中的变量都是保存到 栈内存中的
基本数据类型的值是直接在栈内存中存储

对象是保存到 堆内存中的
每创建一个新的对象,就会在堆内存中开辟出一个新的空间,而变量保存的是对象的 内存地址(对象的引用),如果两个变量保存的是同一个对象应用,当一个通过一个变量修改属性时,另一个也会因地址指向的原因受到影响。

基本类型数据的拷贝方式

对于基本类型数据的拷贝就是一个值赋值到另一个过程中,修改其中一个值,另一个也不会受到影响。

let a = 1;
let b = a; //把a的拷贝到b
a = 3;
console.log(a); //3
console.log(b); //1

在这里插入图片描述
基本类型数据的拷贝在内存过程大概和下面图:
JavaScript中的浅拷贝和深拷贝?他们的区别是什么?_第1张图片

引用数据的拷贝方式

对于引用数据的拷贝,本质是拷贝了对象的储存地址,拷贝后的变量最终还是指向同一个对象,如果修改其中一个变量中的值,另一个指向对象的变量也会跟着更改。


数组的浅拷贝

let oldArray = [1,4,"木龙","刀圭","意马"];
let newArray = oldArray;//进行拷贝

oldArray[0] = "江流";//修改oldArray的值

console.log("oldArray:",oldArray);
console.log("newArray:",oldArray);

在这里插入图片描述
数组也是对象,这就是对象的一种浅拷贝方式。
引用类型数据的拷贝在内存过程大概下面图一样:
JavaScript中的浅拷贝和深拷贝?他们的区别是什么?_第2张图片
当我们修改oldArray[0] = "江流"的时候,因为在拷贝的时候只是将oldArray所指向的地址赋值给newArray,当通过oldArray去修改堆空间的中值时,也会导致打印newArray的值也会发生改变。这种方式就是浅拷贝。
JavaScript中的浅拷贝和深拷贝?他们的区别是什么?_第3张图片


对象的浅拷贝

var  oldObj = {
    name:"心猿",
    age:2000
}

var newObj = oldObj;//浅拷贝

oldObj.age = 5000;//修改年龄

console.log("oldObj:",oldObj);
console.log("newObj:",newObj);

在这里插入图片描述


浅拷贝和深拷贝的概念

浅拷贝:完成拷贝后可能存在彼此之间操作互相影响的就是浅拷贝

深拷贝:完成拷贝后彼此之间操作绝不会有互相影响的就是深拷贝

也有其他解释:浅拷贝是拷贝一层,深层次的对象级别的就拷贝引用;深拷贝是拷贝多层,每一级别的

数据都会拷贝出来


深拷贝

JSON.parse()、JSON.stringify()

语法:

var oldObj = {
    name: "心猿",
    age: 2000
}

var newObj = JSON.parse(JSON.stringify(oldObj));//拷贝

newObj.age = 5000;//修改年龄

console.log("oldObj:", oldObj);
console.log("newObj:", newObj);

在这里插入图片描述
粗暴简单,但是也有缺点。
缺点:
可能会影响数剧,函数无法通过这个拷贝,日期类型的数据会变成字符串。


递归

思路:
在对属性值进行拷贝的时候,先判断属性值的类型,如果是对象,就用递归调用深拷贝函数,如果不是,就直接拷贝。

function deepCopy(obj) {
    if (typeof obj[key] === 'object') return;
    if (Array.isArray(obj)) {//判断是否是数组还是对象
        var newObj = [];
    }
    else {
        var newObj = {};
    }
    for (var key in obj) {
        if (typeof obj[key] === 'object' && !(obj[key] instanceof Date)) {
            newObj[key] = deepCopy(obj[key]);//使用递归进行拷贝
        }
        else {
            newObj[key] = obj[key];
        }
    }
    return newObj
}

测试代码:

var oldObj = {
    name: "心猿",
    gender: "男",
    age: 2000,
    power: {
        skill: "七十二变"
    }
}

var newObj = deepCopy(oldObj);//调用深拷贝


//修改oldObj中的属性值不会改变newObj中的属性值

oldObj.name = "意马";
oldObj.age = 1500;
oldObj.power.skill = "化身为白龙";

console.log("oldObj:", oldObj);
console.log("newObj:", newObj);


/*----------------------深拷贝代码---------------------------------*/
function deepCopy(obj) {
    if (typeof obj[key] === 'object') return;
    if (Array.isArray(obj)) {//判断是否是数组还是对象
        var newObj = [];
    }
    else {
        var newObj = {};
    }
    for (var key in obj) {
        if (typeof obj[key] === 'object' && !(obj[key] instanceof Date)) {
            newObj[key] = deepCopy(obj[key]);//使用递归进行拷贝
        }
        else {
            newObj[key] = obj[key];
        }
    }
    return newObj
}

在这里插入图片描述
其中深拷贝代码简化

function deepCopy(obj) {
    if (typeof obj !== 'object') return;
    let result = obj instanceof Array ? [] : {};
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            result[key] = typeof obj[key] === 'object' 
            && !(obj[key] instanceof Date) ? deepCopy(obj[key]) : obj[key];
        }
    }
    return result;

你可能感兴趣的:(正在路上的前端攻城狮的烂笔记,#,JavaScript,es6,前端,ecmascript)