← 返回首页
Javascript的浅拷贝与深拷贝
发表时间:2022-09-01 23:21:59
Javascript的浅拷贝与深拷贝

1.浅拷贝

浅拷贝:shallow copy,简单说,就是拷贝A对象里面的数据,但是不拷贝A对象里面的子对象。

常用的浅拷贝方式: - for in 循环 - 展开语法 - Object.assign

1).使用for in 实现浅拷贝

let person = {
    name: 'zhangsan',
    age: 20,
    gender: '女',
    car:{
        brand: 'BMW',
        price : 200000,
        color: 'red'
    }
}

let p = {}
for(let key in person) {
    //key是当前属性名, obj[k]是当前属性值
    p[key] = person[key]
}

console.log(p)
p.gender = '男';
p.car.brand = 'BENZ';

console.log("-------p object-------")
console.log(p)
console.log("-------person object-------")
console.log(person)

运行结果:

{                                                     
  name: 'zhangsan',                                   
  age: 20,                                            
  gender: '女',                                       
  car: { brand: 'BMW', price: 200000, color: 'red' }  
}                                                     
-------p object-------                                
{                                                     
  name: 'zhangsan',                                   
  age: 20,                                            
  gender: '男',                                       
  car: { brand: 'BENZ', price: 200000, color: 'red' } 
}                                                     
-------person object-------                           
{                                                     
  name: 'zhangsan',                                   
  age: 20,                                            
  gender: '女',                                       
  car: { brand: 'BENZ', price: 200000, color: 'red' } 
}                              

2).使用展开语法实现浅拷贝

let person = {
    name: 'zhangsan',
    age: 20,
    gender: '女',
    car:{
        brand: 'BMW',
        price : 200000,
        color: 'red'
    }
}
//展开语法实现浅拷贝
let p = {
    ...person
}

console.log(p)

p.gender = '男'
p.car.brand = 'BENZ';

console.log("-------p object-------")
console.log(p)
console.log("-------person object-------")
console.log(person)

运行结果:

{                                                     
  name: 'zhangsan',                                   
  age: 20,                                            
  gender: '女',                                       
  car: { brand: 'BMW', price: 200000, color: 'red' }  
}                                                     
-------p object-------                                
{                                                     
  name: 'zhangsan',                                   
  age: 20,                                            
  gender: '男',                                       
  car: { brand: 'BENZ', price: 200000, color: 'red' } 
}                                                     
-------person object-------                           
{                                                     
  name: 'zhangsan',                                   
  age: 20,                                            
  gender: '女',                                       
  car: { brand: 'BENZ', price: 200000, color: 'red' } 
}                              

我们发现由于是浅拷贝,所以改变p对象里car的属性也同时修改了person对象的car属性,因为这两个对象的car引用指向了同一个汽车对象。

3).Object.assign

let person = {
    name: 'zhangsan',
    age: 20,
    gender: '女',
    car:{
        brand: 'BMW',
        price : 200000,
        color: 'red'
    }
}

let p ={};
Object.assign(p, person); //浅拷贝

console.log(p)

p.gender = '男'
p.car.brand = 'BENZ';

console.log("-------p object-------")
console.log(p)
console.log("-------person object-------")
console.log(person)

运行结果与上面两种完全相同。

2.深拷贝

深拷贝:deep copy,简单说就是不仅要拷贝A对象里面的数据,也要拷贝它里面的子对象。

常见的深拷贝实现方式: - JSON.stringify
- 自定义递归算法 - lodash

1).JSON.stringify 由于基本数据类型默认都是深拷贝,我们可以使用JSON.stringify把对象转换为字符串,实现深拷贝。但是这种方式无法拷贝function和undefined类型的属性。

let person = {
    name: 'zhangsan',
    age: 20,
    gender: '女',
    car:{
        brand: 'BMW',
        price : 200000,
        color: 'red'
    },
    eat:()=>{
        console.log(this.name+"is eating now...");
    },
    assets: undefined
}

let jsonStr = JSON.stringify(person);
let p = JSON.parse(jsonStr)

console.log(p)
p.gender = '男'
p.car.brand = 'BENZ';

console.log("-------p object-------")
console.log(p)
console.log("-------person object-------")
console.log(person)

运行结果:

{                                                    
  name: 'zhangsan',                                  
  age: 20,                                           
  gender: '女',                                      
  car: { brand: 'BMW', price: 200000, color: 'red' } 
}                                                    
-------p object-------                               
{                                                    
  name: 'zhangsan',
  age: 20,
  gender: '男',
  car: { brand: 'BENZ', price: 200000, color: 'red' }
}
-------person object-------
{ 
  name: 'zhangsan',
  age: 20,
  gender: '女',
  car: { brand: 'BMW', price: 200000, color: 'red' },
  eat: [Function: eat],
  assets: undefined
}

2).自定义递归算法

//封装函数
function deepCopy(newObj,obj) {
    for(let key in obj) {
        //判断属性值属于哪种数据类型
        //属性值 obj[key]
        //1.判断这个值是否为数组(数组也属于特殊对象,也是引用类型数据)
        if(obj[key] instanceof Array) {
            newObj[key] = []
            deepCopy(newObj[key],obj[key]) //运用递归,把原对象属性值给新对象
            //判断这个值是否为对象
        } else if(obj[key] instanceof Object) {
            newObj[key] = {}
            deepCopy(newObj[key],obj[key]) //运用递归,把原对象属性值给新对象
        } else {
            //若是普通数据类型
            newObj[key] = obj[key]
        }
    }
}

let person = {
    name: 'zhangsan',
    age: 20,
    gender: '女',
    car:{
        brand: 'BMW',
        price : 200000,
        color: 'red'
    },
    eat:()=>{
        console.log(this.name+"is eating now...");
    },
    assets: undefined
}

let p = {};
deepCopy(p,person);

console.log(p)
p.gender = '男'
p.car.brand = 'BENZ';

console.log("-------p object-------")
console.log(p)
console.log("-------person object-------")
console.log(person)

运行结果:

{                                                     
  name: 'zhangsan',                                   
  age: 20,                                            
  gender: '女',                                       
  car: { brand: 'BMW', price: 200000, color: 'red' }, 
  eat: {},                                            
  assets: undefined                                   
}                                                     
-------p object-------                                
{                                                     
  name: 'zhangsan',                                   
  age: 20,                                            
  gender: '男',                                       
  car: { brand: 'BENZ', price: 200000, color: 'red' },
  eat: {},
  assets: undefined
}
-------person object-------
{
  name: 'zhangsan',
  age: 20,
  gender: '女',
  car: { brand: 'BMW', price: 200000, color: 'red' },
  eat: [Function: eat],
  assets: undefined
}

这种方式同样存在,无法拷贝function类型的属性。

3).lodash

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>lodash实现深拷贝</title>
    <!--CDN引入lodash类-->
    <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/lodash.js/4.17.21/lodash.min.js"></script>
</head>
<body>
<script>
    //使用lodash实现对象深拷贝。
    let person = {
        name: 'zhangsan',
        age: 20,
        gender: '女',
        car:{
            brand: 'BMW',
            price : 200000,
            color: 'red'
        },
        eat:()=>{
            console.log(this.name+"is eating now...");
        },

        assets: undefined
    }
    //lodash实现深拷贝
    let p = _.cloneDeep(person);
    console.log(p);

    p.gender = '男'
    p.car.brand = 'BENZ';

    console.log("-------p object-------")
    console.log(p)
    console.log("-------person object-------")
    console.log(person)
</script>
</body>
</html>

运行结果:

小结: 1. 浅拷贝:shallow copy,简单说,就是拷贝A对象里面的数据,但是不拷贝A对象里面的子对象。引用类型默认都是浅拷贝。浅拷贝常见的实现方式有:for in 循环,展开语法和Object.assign等等。 2. 深拷贝:deep copy,简单说就是不仅要拷贝A对象里面的数据,也要拷贝它里面的子对象。基本类型默认都是深拷贝。深拷贝常见的实现方式有:JSON.stringify,自定义递归算法和lodash工具类。 3. 推荐使用lodash工具类来轻松实现对象的深拷贝。