什么是引用赋值、浅拷贝和深拷贝,以及手拉手带你实现深拷贝

概述

在开始实现深拷贝之前,有必要首先了解一下引用赋值、浅拷贝和深拷贝之间的关系。他们都是复制对象时经常采用的方式,有一定的联系和区别:

  1. 引用赋值:将一个对象赋值给另一个变量时,实际上是将对象的引用地址赋值给了另一个变量,即两个变量指向同一块内存地址的对象。这意味着,对其中一个变量所指向的对象进行修改,另一个变量也会受到影响

  2. 浅拷贝:复制对象时,只复制对象中的基本类型属性和对象引用地址,而不复制对象的子对象或数组的引用地址。这样,当对复制后的对象进行修改时,不会影响原始对象,如果原始对象中包含的子对象或数组的引用地址发生改变复制后的对象和原始对象都会受到影响。

  3. 深拷贝:复制对象时,完整复制对象中的所有属性和子属性,包括嵌套对象和数组。这样,当对复制后的对象进行修改时,不会影响原始对象和原始对象中的子对象或数组。

总之,引用赋值会使两个变量指向同一个对象浅拷贝只复制基本类型属性和对象引用地址,而深拷贝会完整复制所有属性和子属性。因此,在不同的场景中需要根据需要选择不同的方式。

说了这么多,我们可能还是有些糊涂,没事,举个例子就懂了!
啥也不说了,看代码吧

var a = 3
// 浅拷贝
var b = a
b = 5
console.log(a, b) // 3,5 

const s1 = Symbol()
const s2 = Symbol()
const info = {
  name: "Machigen",
  friend: {
    name: "kobe"
  },
  foo: function() {
    console.log("foo function")
  },
  [s1]: "abc",
  s2: s2
}

// 引用赋值:更改obj或info中的任何一个,另一个就会改变
const obj = info
console.log(info === name)  // true

// 浅拷贝
const obj2 = { ...info }
obj2.name = 'Messi'
obj2.friend.name = 'Taylor'
console.log(info.name, obj2.name) // Machigen, Messi
console.log(info.friend.name, obj2.friend.name) // Taylor, Taylor

// 深拷贝
const obj3 = JSON.Stringfy(info)
obj3.name = 'Messi'
obj3.friend.name = 'Taylor'
console.log(info.name, obj3.name) // Machigen, Messi
console.log(info.friend.name, obj3.info.name) // kobe, Taylor

好了,这下我们应该知道这三者的大致联系与区别了吧,接下来一起来实现 一下吧

1.基本实现

// 判断一个标识符是否是一个对象类型
function isObject(value) {
  //  array, object => object
  // function => function => object
  // null => object
  // 但要将null排除在外
  const valueType = typeof value
  return (value !== null) && (valueType === "object" || valueType === "function")
}

function deepCopy(originValue) {
	// 判断传入的originValue是否是一个对象类型
	if(!isObject(originValue))	
		return originValue
	const newObject = {}
	for(let key in originValue) {
		newObject[key] = deepCopy(originValue[key])
	}
	return newObject
}

// 测试代码
const obj = {
  name: "Messi",
  age: 18,
  friend: {
    name: "Jason",
    address: {
      city: "上海"
    }
  }
}

const newObj = deepClone(obj)
console.log(newObj === obj)  // false

obj.friend.name = "kobe"
obj.friend.address.city = "北京"
console.log(newObj)

2.对各种类型进行判断

function isObject(value) {
  const valueType = typeof value
  return (value !== null) && (valueType === "object" || valueType === "function")
}

function deepClone(originValue) {
  // 判断是否是一个Set类型
  if (originValue instanceof Set) {
    return new Set([...originValue])
  }

  // 判断是否是一个Map类型
  if (originValue instanceof Map) {
    return new Map([...originValue])
  }

  // 判断如果是Symbol的value, 那么创建一个新的Symbol
  if (typeof originValue === "symbol") {
    return Symbol(originValue.description)
  }

  // 判断如果是函数类型, 那么直接使用同一个函数
  if (typeof originValue === "function") {
    return originValue
  }

  // 判断传入的originValue是否是一个对象类型
  if (!isObject(originValue)) {
    return originValue
  }

  // 判断传入的对象是数组, 还是对象
  const newObject = Array.isArray(originValue) ? []: {}
  for (const key in originValue) {
    newObject[key] = deepClone(originValue[key])
  }

  // 对Symbol的key进行特殊的处理
  const symbolKeys = Object.getOwnPropertySymbols(originValue)
  for (const sKey of symbolKeys) { 
    newObject[sKey] = deepClone(originValue[sKey])
  }
  
  return newObject
}


// 测试代码
let s1 = Symbol("aaa")
let s2 = Symbol("bbb")

const obj = {
  name: "Machigen",
  age: 18,
  friend: {
    name: "Lee",
    address: {
      city: "广州"
    }
  },
  // 数组类型
  hobbies: ["abc", "cba", "nba"],
  // 函数类型
  foo: function(m, n) {
    console.log("foo function") 
    return 123
  },
  // Symbol作为key和value
  [s1]: "abc",
  s2: s2,
  // Set/Map
  set: new Set(["aaa", "bbb", "ccc"]),
  map: new Map([["aaa", "abc"], ["bbb", "cba"]])
}

const newObj = deepClone(obj)
console.log(newObj === obj) // false

obj.friend.name = "kobe"
obj.friend.address.city = "成都"
console.log(newObj)
console.log(newObj.s2 === obj.s2) // false
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值