javascript进阶知识15- 对象的浅拷贝与深拷贝

80 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情

浅拷贝与深拷贝

  • 浅拷贝:可以理解为一个新的对象只是简单的复制了原有对象的内存地址
    新旧对象指向的都是同一个引用地址

  • 深拷贝:完全开辟出的一个新空间来存放和旧对象中一模一样的数据,两者只是内容一样而已,
    改变原有对象,新复制出来的对象不会受到任何影响

浅拷贝

浅拷贝就是通过赋值的方式进行拷贝,那为什么说这是浅拷贝呢?就是因为赋值的方式只会把对象的表层赋值给一个新的对象,如果里面有属性值为数组或者对象,那么就只会拷贝到该属性在栈空间的指针地址,新对象的这些属性数据就会跟旧对象公用一份,也就是说两个地址指向同一份数据,一个改变就会都改变。

let person = {
    name:'ly',
    hobby:['play','sleep','eat']
}
let newPerson = Object.assign({},person)
newPerson.hobby.push('football')

image.png

我们发现我们只是修改了newPerson对象上的hobby,但是person上面的hobby也跟着改变了。

所以,当对象中的属性有引用类型时,有时候使用浅拷贝就不太合适了。那么一般的浅拷贝有哪些呢? 我们发现,使用Object.assign()合并对象,里面的属性是浅拷贝.

let person = {
    name:'ly',
    hobby:['play','sleep','eat']
}
let person2 = {...person}
person2.hobby.push('swim')

image.png

我们发现ES6的扩展运算符也是浅拷贝。

此外,还有直接赋值也是浅拷贝。

let person = {
    name:'ly',
    hobby:['play','sleep','eat']
}
let person2 = person 
person2.hobby.push('swim')

image.png

深拷贝

我们发现我们有时候需要的是获得某个对象上面的所有属性,但是修改新对象不会对源对象产生影响,这就需要使用深拷贝了。

当拷贝的目标只有对象

let user = {
  name: "ly",
  obj: {
    height: "170",
    age: "18",
  },
};
function copy(obj) {
  let res = {};
  for (const key in obj) {
    // 此处用到递归
    // 如果循环到对象里面还是对象,就循环里面的对象,层层深入,一直循环到没有对象为止
    res[key] = typeof obj[key] === "object" ? copy(obj[key]) : obj[key];
  }
  return res;
}
let newuser = copy(user);
newuser.obj.age = 19;

image.png

当拷贝的目标既有对象也有数组

let person = {
  name: "ly",
  info: {
    age: "18",
    height: "170",
  },
  data: [
    {
      id: "1",
      title: "css",
    },
  ],
};
function copy(obj) {
  // 先判断拷贝目标是对象还是数组,用instanceof判断原型是Array还是Object
  let res = obj instanceof Array ? [] : {};
  for (const [key, value] of Object.entries(obj)) {
    res[key] = typeof value === "object" ? copy(value) : value;
  }
  return res;
}
let newPerson = copy(person);
newPerson.data[0].title = "javascript";

image.png

函数也属于对象,它的key就是函数名,value就是函数体。

let person = {
    name:'ly',
    sayName() {
        console.log(this.name)
    }
}

for(const [key,value] of Object.entries(person)) {
    console.log(key,value)
}

image.png

通过 json反序列化实现深拷贝

let person = {
  name: 'ly',
  age: 18,
  hobby: ['eat', 'sleep', 'play'],
  obj: {
    index: 1,
    title: 'css'
  },
  say: function () {
    console.log('hello css')
  }
}

function copy(obj) {
  let _obj = JSON.stringify(obj)
  let newObj = JSON.parse(_obj)
  return newObj
}

let son = copy(person)
son.hobby.push('看电视')

image.png

但是我们发现这种方式不能拷贝函数,person本来有say函数的,但是通过json反序列化拷贝给son后,我们发现son身上没有了say函数。