一、赋值
- 把一个对象a赋值给一个对象b,相当于把一个对象b的地址指向对象a的地址,他们指向同一片内存,b不过是a的别名,是引用;所以,他们实际上是同一个对象。
以下图直接赋值的例子,a对象中有两个属性,一个是name,一个是对象属性action;为什么要弄一个对象属性,这个会涉及到后面的浅拷贝和深拷贝问题,这也是他们之间的区别。
我们可以通过严格相等运算符"==="来检测二者是否指向同一个地址。
- 以刚才的例子为例,如下图所示。给b的name属性赋值'李四',给b的对象属性action的sing属性赋值'后来',a也发生了改变。
即:直接赋值,修改赋值后的对象b的非对象属性,也会影响原对象a的非对象属性;修改赋值后的对象b的对象属性,也会影响原对象a的对象属性。
二、浅拷贝
- 浅拷贝只会赋值对象的非对象属性,不会指向同一个地址。ES6中有个浅拷贝的方法Object.assign(target, ...sources)。以之前直接赋值的对象为例,如下图所示。
- 修改赋值后的对象b的非对象属性,不会影响原对象a的非对象属性;修改赋值后的对象b的对象属性,却会影响原对象a的对象属性,如下图所示。
- es6中还有一个扩展运算符"..."也可以实现浅拷贝,还是以之前的对象为例,可以写成这种形式:var b= { ...a};如下图所示。
- 也可以用 for(let key in object){} 赋值来实现浅拷贝,如下图所示
三、深拷贝
- 深拷贝会另外拷贝一份一个一模一样的对象,但是不同的是会从堆内存中开辟一个新的区域存放新对象,新对象跟原对象不再共享内存,修改赋值后的对象b不会改到原对象a。
即深拷贝,修改赋值后的对象b的非对象属性,不会影响原对象a的非对象属性;修改赋值后的对象b的对象属性,也不会影响原对象a的对象属性。而且,二者不指向同一个对象。
比较笨一点的办法就是将自己需要的数据自己封装起来。
let object={
repayment:this.ruleForm.repayment,
interestType:this.ruleForm.interestType,
productDeadline:this.ruleForm.productDeadline,
circumstancesOfDetention:this.ruleForm.circumstancesOfDetention,
}
this.tableData.push(object);
- 但是,这样明显会使代码很臃肿,而且,这还是在需要的数据只有4条的情况下,如果这个object需要封装十几条非对象属性的情况下,明显结构不复杂的情况下,这种代码需要改进。
有一种非常简单的方法就是序列化成为一个JSON字符串,将对象的内容转换成字符串的形式,再用JSON.parse()反序列化将JSON字符串变成一个新的对象,这样原对象就与复制后的新对象没了必然的关系。写法如下:
var b=JSON.parse(JSON.stringify(a));如下图所示
- 但是由于用到了JSON.stringify(),这也会导致一系列的问题,因为要严格遵守JSON序列化规则:原对象中如果含有Date对象,JSON.stringify()会将其变为字符串,之后并不会将其还原为日期对象。或是含有RegExp对象,JSON.stringify()会将其变为空对象,属性中含有NaN、Infinity和-Infinity,则序列化的结果会变成null,如果属性中有函数,undefined,symbol则经过JSON.stringify()序列化后的JSON字符串中这个键值对会消失,因为不支持。