Skip to content

浅拷贝与深拷贝

image-20230823225743324

一、什么是浅拷贝和深拷贝

浅拷贝

  • 对于基本数据类型的成员变量,浅拷贝直接进行值传递,也就是将属性值复制了一份给新的成员变量
  • 对于引用数据类型的成员变量,比如成员变量是数组、某个类的对象等,浅拷贝就是引用的传递,也就是将成员变量的引用(内存地址)复制了一份给新的成员变量,他们指向的是同一个事例。在一个对象修改成员变量的值,会影响到另一个对象中成员变量的值。

深拷贝

  • 对于基本数据类型,深拷贝复制所有基本数据类型的成员变量的值
  • 对于引用数据类型的成员变量,深拷贝申请新的存储空间并复制该引用对象所引用的对象,也就是将整个对象复制下来。所以在一个对象修改成员变量的值,不会影响到另一个对象成员变量的值。

深拷贝

使用JSON方法实现

javascript
const obj1 = {name:1}
const obj2 = JSON.parse(JSON.stringify(obj1))
obj1.name = 23
obj2.name  = 2323
console.log(obj1, obj2)

image-20230823223145776

缺点:不能拷贝函数及一些Map、Set结构

使用递归实现

js
// 简单写法
function deepClone(obj){
    let objClone = Array.isArray(obj)?[]:{};
    if(obj && typeof obj==="object"){
        for(key in obj){
            if(obj.hasOwnProperty(key)){
                //判断obj子元素是否为对象,如果是,递归复制
                if(obj[key]&&typeof obj[key] ==="object"){
                    objClone[key] = deepClone(obj[key]);
                }else{
                    //如果不是,简单复制
                    objClone[key] = obj[key];
                }
            }
        }
    }
    return objClone;
}    
let a=[1,2,3,4],
    b=deepClone(a);
a[0]=2;
console.log(a,b);

拷贝函数及以下Map、Set结构

js

// 获取正则表达式 修饰符(标记)
function __getRegExpFlags(re) {
  var flags = '';
  if (re.global) flags += 'g';
  if (re.ignoreCase) flags += 'i';
  if (re.multiline) flags += 'm';
  return flags;
}


// 获取数据类型
function getType(obj){
  return Object.prototype.toString.call(obj).slice(8,-1);
}
function cloneDeep(obj){
 
  const ret = {}
  
  for(let key in obj){
    const value = obj[key];
    let cloneValue = null
    // 如果是函数
    if(typeof value === 'function'){
        cloneValue = value.bind(ret);
    }
    else if(Array.isArray(value)){
      for(let val of value){
        cloneValue = cloneDeep(val)
      }
    }
    // 考虑正则表达式
    else if(getType(value) === "RegExp"){
       cloneValue = new RegExp(value.source, __getRegExpFlags(value));
    }
    else if (getType(value) === "Date") {
       cloneValue = new Date(value.getTime());
      // 处理Map 
    }else if(getType(value) === "Map"){      
       const map = new Map()

      for(let key in value){ 
        map.set(key ,cloneDeep(value[key]))
      }
      cloneValue  = map;
    }
    // 处理Set结构
    else if(getType(value) === "Set"){      
       const set = new Set()

      for(let key in value){ 
        set.set(key ,cloneDeep(value[key]))
      }
      cloneValue  = set;
    }
    else if(getType(value) === "object"){
      cloneValue = cloneDeep(val)
    }else{
      cloneValue = value
    }
    ret[key] = cloneValue
  }
  return ret
}


const obj = {
  re: /hello/,
  f() {},
  date: new Date(),
  map: new Map(),
  list: [1, 2, 3],
  set:new Set([12,3]),
  a: 3,
  b: 4,
};

const objClone = cloneDeep(obj)
// 测试map
obj.map.set("num",1)
console.log(obj.map.get("num"))
// 这里出问题
console.log(objClone.map.get("num"));


obj.set.add(0)
console.log(obj.set)
console.log(objClone.set)


const re = /hello/
console.log(re.source)

使用lodash

js
import {cloneDeep  } from 'lodash'
var objects = [{ 'a': 1 }, { 'b': 2 }];
 
var deep = cloneDeep(objects);
console.log(deep[0] === objects[0]);

前端知识体系 · wcrane