let a = {
name: 'hcc',
info: {
study_info: {
middle_school: {
class: 6,
rant: 2
},
high_school: {
class: 5,
rant: 10
}
}
}
}
let b = {...a};
let c = JSON.parse(JSON.stringify(a));
let d = Object.assign({}, a);
a.name = 'hcc1';
console.log(b.name); // hcc
console.log(c.name); // hcc
console.log(d.name); // hcc
a.info.study_info.middle_school.rant = 3;
console.log(b.info.study_info.middle_school.rant) // 3
console.log(c.info.study_info.middle_school.rant) // 2
console.log(d.info.study_info.middle_school.rant) // 3
a.info.study_info = null; console.log(b.info.study_info) // null console.log(c.info.study_info) // [object object] console.log(d.info.study_info)// null
开发过程中可能会遇到需要复制一个对象的时候,我一般会想到三个方法:a.info.study_info = null;
console.log(b.info.study_info)
console.log(c.info.study_info)
console.log(d.info.study_info)
1. es6 扩展运算符...
这种方法为浅复制,由代码执行结果来看,改变对象第一层的属性不会改变复制之后的对象相应的属性,但是第二层以及深层改变的就会影响到。因此该方法属于浅复制。
2. JSON.parse(JSON.stringify());
这种方法为深复制,可以看到改变深层的属性值,仍然不会影响复制之后的对象的相应值,但是此方法的缺点是当undefined等值的时候复制会不准确,这是因为JSON.stringify拥有以下限制:
1. 转换值如果有 toJSON() 方法,该方法定义什么值将被序列化。
2. 非数组对象的属性不能保证以特定的顺序出现在序列化后的字符串中。
3. 布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值。
4. undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。函数、undefined 被单独转换时,会返回 undefined,如JSON.stringify(function(){})orJSON.stringify(undefined).
5. 对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误。所有以 symbol 为属性键的属性都会被完全忽略掉,即便 replacer 参数中强制指定包含了它们。
6. Date 日期调用了 toJSON() 将其转换为了 string 字符串(同Date.toISOString()),因此会被当做字符串处理。
7. NaN 和 Infinity 格式的数值及 null 都会被当做 null。
8. 其他类型的对象,包括 Map/Set/WeakMap/WeakSet,仅会序列化可枚举的属性。
见https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
3. object.assign({}, a);
因为 Object.assign()拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用。
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
那么应该用怎样的方法能够实现深拷贝呢?
1. Jquery extend 方法
$.extend(true, {}, indexTree)
2. lodash 提供了 lodash.cloneDeep()实现深拷贝
3. 自己使用递归的方法实现深拷贝。