javascript中的浅拷贝和深拷贝

Posted 低代码布道师

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了javascript中的浅拷贝和深拷贝相关的知识,希望对你有一定的参考价值。

谈这个话题特指javascript中的对象,我们使用赋值的语法来定义一个对象,其实只是获取了这个对象的引用

let user = {
  name: "John"
};

这里的user变量只是指向了对象,是对象的一个引用

如果我们再定义一个变量,并且把user赋值给变量

let user = { name: "John" };

let admin = user; // copy the reference

这里的admin也指向了变量,user和admin都是对象的引用

let user = { name: 'John' };

let admin = user;

admin.name = 'Pete'; // changed by the "admin" reference

alert(user.name); // 'Pete', changes are seen from the "user" reference

因为指向的是一个对象,所以通过admin来改变对象的属性,再用user去访问属性时会得到一个值,是改变后的Pete

let a = {};
let b = a; // copy the reference

alert( a == b ); // true, both variables reference the same object
alert( a === b ); // true

因为a和b都指向相同的对象,所以他们的值和类型都相同

let a = {};
let b = {}; // two independent objects

alert( a == b ); // false

a和b是两个对象,所以他们不相等

变量定义和赋值不能实现对象的拷贝,那我想复制出一模一样的对象怎么办?

let user = {
  name: "John",
  age: 30
};

let clone = {}; // the new empty object

// let's copy all user properties into it
for (let key in user) {
  clone[key] = user[key];
}

// now clone is a fully independent object with the same content
clone.name = "Pete"; // changed the data in it

alert( user.name ); // still John in the original object

可以迭代对象的属性做赋值,但是这样稍显麻烦,javascript有现成的API可以做到这一件事

Object.assign(dest, [src1, src2, src3...])

通过这个API就可以实现将对象的属性进行合并赋值给新的对象

例如:

let user = { name: "John" };

let permissions1 = { canView: true };
let permissions2 = { canEdit: true };

// copies all properties from permissions1 and permissions2 into user
Object.assign(user, permissions1, permissions2);

// now user = { name: "John", canView: true, canEdit: true }

如果要是遇到属性相同会进行覆盖

let user = { name: "John" };

Object.assign(user, { name: "Pete" });

alert(user.name); // now user = { name: "Pete" }

我们也可以采用简写的语法

let user = {
  name: "John",
  age: 30
};

let clone = Object.assign({}, user);

这样就复制出一个对象来,clone就是复制后的对象

如果对象的属性也是对象,那这种情况复制会出现什么情况呢?

let user = {
  name: "John",
  sizes: {
    height: 182,
    width: 50
  }
};

alert( user.sizes.height ); // 182
let user = {
  name: "John",
  sizes: {
    height: 182,
    width: 50
  }
};

let clone = Object.assign({}, user);

alert( user.sizes === clone.sizes ); // true, same object

// user and clone share sizes
user.sizes.width++;       // change a property from one place
alert(clone.sizes.width); // 51, see the result from the other one

这样的复制叫浅拷贝,因为只是拷贝了对象的引用,如果原对象的值发生改变会影响到复制出来的新对象的值,这样就造成了混乱。所以当对象的属性也是对象时,使用浅拷贝的API就行不通了,这个时候我们需要使用深拷贝。

var objects = [{ 'a': 1 }, { 'b': 2 }];
 
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false

深拷贝会递归的迭代属性,属于彻底的复制出一个新的对象来。

另外还需注意的就是const

const user = {
  name: "John"
};

user.name = "Pete"; // (*)

alert(user.name); // Pete

使用const后只是说这个对象的引用不能改变了,并不意味着对象的属性不可以改变

以上是关于javascript中的浅拷贝和深拷贝的主要内容,如果未能解决你的问题,请参考以下文章

javascript中的浅拷贝和深拷贝

JavaScript学习(七十八)—实现对数据的浅拷贝和深拷贝

python中的浅拷贝和深拷贝

js对象浅拷贝和深拷贝详解

C#的浅拷贝和深拷贝

python中的浅拷贝和深拷贝