对象的赋值,浅拷贝和深拷贝

注意:这里说的深浅拷贝都是在引用数据类型上描述的。

赋值

直接拷贝内存地址(新对象变,原对象也变)

下面的newObj直接拷贝了obj的内存地址,它们指向同一个对象,所以修改任何属性,它们都会相互影响。

const obj = {
  name: '小明',
  hobbies:['唱','跳','rap']
};
const newObj = obj
newObj.name = '张三'
newObj.hobbies[0] = '打篮球'
console.log(JSON.stringify(obj));
// {"name":"张三","hobbies":["打篮球","跳","rap"]}
console.log(JSON.stringify(newObj));
// {"name":"张三","hobbies":["打篮球","跳","rap"]}

浅拷贝

基本数据类型是直接拷贝值,引用数据类型是拷贝内存地址

下面的newObj,对于name属性,是直接拷贝值;对于hobbies属性,是拷贝内存地址。

ES6的扩展运算符实现

const obj = {
  name: '小明',
  hobbies:['唱','跳','rap']
};
// 浅拷贝obj对象
const newObj = {...obj}
newObj.name = '张三'
newObj.hobbies[0] = '打篮球'
console.log(JSON.stringify(obj));
// {"name":"小明","hobbies":["打篮球","跳","rap"]}
console.log(JSON.stringify(newObj));
// {"name":"张三","hobbies":["打篮球","跳","rap"]}

Object.assign实现

const obj = {
  name: '小明',
  hobbies: ['唱', '跳', 'rap']
};
// 浅拷贝obj对象
const newObj = Object.assign({},obj)
newObj.name = '张三'
newObj.hobbies[0] = '打篮球'
console.log(JSON.stringify(obj));
// {"name":"小明","hobbies":["打篮球","跳","rap"]}
console.log(JSON.stringify(newObj));
// {"name":"张三","hobbies":["打篮球","跳","rap"]}

shallowCopy函数实现

const obj = {
  name: '小明',
  hobbies: ['唱', '跳', 'rap']
};
const newObj = shallowCopy(obj)
newObj.name = '张三'
newObj.hobbies[0] = '打篮球'
console.log(JSON.stringify(obj));
// {"name":"小明","hobbies":["打篮球","跳","rap"]}
console.log(JSON.stringify(newObj));
// {"name":"张三","hobbies":["打篮球","跳","rap"]}

// 浅拷贝函数
function shallowCopy(obj){
  const newObj = {}
  for(let key in obj){
    newObj[key] = obj[key]
  }
  return newObj
}

深拷贝

直接在堆内存中开辟新的一块空间(新对象变,原对象不变)

JSON.parse和JSON.stringify实现

下面的newObj,指向了一个和obj一模一样的新对象。无论是修改newObj中的基本类型数据,还是引用类型数据,obj都不会发生变化。

const obj = {
  name: '小明',
  hobbies:['唱','跳','rap']
};
// 深拷贝obj对象
const newObj = JSON.parse(JSON.stringify(obj))
newObj.name = '张三'
newObj.hobbies[0] = '打篮球'
console.log(JSON.stringify(obj));
// {"name":"小明","hobbies":["唱","跳","rap"]}
console.log(JSON.stringify(newObj));
// {"name":"张三","hobbies":["打篮球","跳","rap"]}

不过,JSON.stringify方法有个缺点:如果数据包含函数或者undefined,则序列化后,它们的键值对会丢失。

const obj = {
  name: '小明',
  hobbies: ['唱', '跳', 'rap'],
  fn() {
    console.log(123);
  },
  age: undefined
};
const newObj = JSON.parse(JSON.stringify(obj))
console.log(newObj);
// 输出的结果没有fn和age属性

deepCopy函数实现

const obj = {
  name: '小明',
  hobbies: ['唱', '跳', 'rap']
};
const newObj = deepCopy(obj)
newObj.name = '张三'
newObj.hobbies[0] = '打篮球'
console.log(JSON.stringify(obj));
// {"name":"小明","hobbies":["唱","跳","rap"]}
console.log(JSON.stringify(newObj));
// {"name":"张三","hobbies":["打篮球","跳","rap"]}

// 深拷贝函数
function deepCopy(obj) {
  if (typeof (obj) !== 'object' || typeof (obj) == null) return obj
  const newObj = Array.isArray(obj) ? [] : {}
  for (let key in obj) {
    // 递归调用
    newObj[key] = deepCopy(obj[key])
  }
  return newObj
}

猜你喜欢

转载自blog.csdn.net/qq_52607834/article/details/129404355