深拷贝与浅拷贝

先了解一下js的数据类型

js数据类型分两种:

第一种是基本数据类型:String(字符串)、Number(数字) 、Boolean(布尔值)、Null(空)、Undefined(未定义)

第二种是引用数据类型:Object(对象)、Array(数组)、Function(函数)

基本数据类型的变量是存放在栈内存,引用数据类型是放在堆内存中的,基本数据类型保存的是值,而引用数据类型一般保存的是对象的地址。
如果我们单纯的复制的话,可能就只是复制对象的地址,那么这就是浅拷贝,如果是克隆了对象,改变了引用对象的地址,那么就是深拷贝。

一、 浅拷贝

对于浅拷贝而言,就是只拷贝对象的引用,而不深层次的拷贝对象的值,多个对象指向堆内存中的同一对象,任何一个修改都会使得所有对象的值修改,因为它们公用一条数据

二、深拷贝

我们在实际的项目中,肯定不能让每个对象的值都指向同一个堆内存,这样的话不便于我们做操作,所以自然而然的诞生了深拷贝
深拷贝作用在引用类型上!例如:ObjectArray
深拷贝不会拷贝引用类型的引用,而是将引用类型的值全部拷贝一份,形成一个新的引用类型,这样就不会发生引用错乱的问题,使得我们可以多次使用同样的数据,而不用担心数据之间会起冲突。

例:

//浅拷贝
let obj = {a:1,b:{c:1}}
let obj1 = {...obj1} 
obj.b === obj1.b 
//深拷贝
let obj3 = {a:1,b:{c:1}}
let obj4 = {..obj3,b:{...obj3.b}}
obj3.b === obj4.b

为什么要进行深拷贝

首先看下如下代码

let a = b = 2
a = 3
console.log(a)
console.log(b)
let c = d = [1,2,3]
let e = f = {a:1,b:2,c:3}
c[0] = 2
e.a = 2
console.log(d[0])
console.log(f.a)

会发现,同一个Array或者Object赋值给两个不同变量时,变量指向的是同一个内存地址,所以就会造成其中一个变量改变属性值,同时改变了另外一个变量的对应属性值。

而大多数实际项目中,我们想要的结果是两个变量(初始值相同)互不影响。所以就要使用到拷贝(分为深浅两种)

深浅拷贝的区别:

简而化之:
浅拷贝和深拷贝的区别是:看复制的子对象是否在堆内存中指向一个新的地址

那么怎么实现一个深拷贝呢?
实现思路:

检查类型,判断类型是否为引用类型,是就进行深拷贝,否则浅拷贝
使用递归
检查环,判断当前引用是否指向自身,避免进入死循环
需要忽略原型

简易版实现代码(只处理了Object和Array两种引用类型):

function deepClone(obj){
  // 判断当前对象是对象还是数组
  let result = Array.isArray(obj)?[]:{};
  if(obj && typeof obj === "object"){
    for(let key in obj){
       // 判断是否为自身属性
      if(obj.hasOwnProperty(key)){
        if(obj[key] && typeof obj[key] === "object"){
          //子元素为对象,进入递归
          result[key] = deepClone(obj[key]);
        }else{
          result[key] = obj[key];
        }
      }
    }
  }
  return result;
}


深拷贝的三种方式

深拷贝的方法

//待拷贝的对象
let a = {
    name: '张三',
    grade: {
        chinese: 23,
        math: 90,
    },
    sex: '男',
    friend: [{id: '李四'},'王五'],
    date: new Date().toString(),
    call() {
        console.log('call()')
    }
}

JSON 对象

JSON.parse(JSON.stringify(a)): a 只能是扁平对象
//不能拷贝 function,会直接丢弃,ye


console.log('JSON 深拷贝a', JSON.parse(JSON.stringify(a)))

Object.assign(target,source)

//如果只有一级属性,则就是深拷贝
//如果一级属性里面有引用数据类型,则这个只是浅拷贝了
console.log(Object.assign({},a))

for in 递归拷贝

/* for in 递归拷贝会将 原型上的属性方法全部拷贝过来 */
function clone(source) {
    let target = source instanceof Array ? [] : {}
    for (let key in source) {
        if (typeof source[key] === 'object') {
            target[key] = clone(source[key])
        } else {
            target[key] = source[key]
        }
    }
    return target
}
//函数还是同一个函数,函数没有做到深拷贝
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值