js对象浅拷贝与深拷贝
- javascript中Object、Array是引用类型,栈内存中存储内存地址,堆内存存储值,所以在引用类型的拷贝中,存在浅拷贝、深拷贝。下文将经过示例加以说明。
- 由于基本类型和引用类型的区别,注意函数值传递的区别,这里不加以详细说明。
浅拷贝
- 若是对象里只用值类型的属性,能够使用扩展符(...)或 Object.assign(...)拷贝
<!--扩展符-->
var obj = { foo: "foo", bar: "bar" };
var copy = { ...obj }; // Object { foo: "foo", bar: "bar" }
<!--assign-->
var obj = { foo: "foo", bar: "bar" };
var copy = Object.assign({}, obj); // Object { foo: "foo", bar: "bar" }
复制代码
- 注意,上述两种方法均可用于将属性值从多个源对象复制到目标对象,示例
var obj1 = { foo: "foo" };
var obj2 = { bar: "bar" };
var copySpread = { ...obj1, ...obj2 }; // Object { foo: "foo", bar: "bar" }
var copyAssign = Object.assign({}, obj1, obj2); // Object { foo: "foo", bar: "bar" }
复制代码
- 上述方法的问题在于,对于具备属性自己对象的对象,只复制引用,示例
var foo = { a: 0 , b: { c: 0 } };
var copy = { ...foo };
copy.a = 1;
copy.b.c = 2;
console.dir(foo); // { a: 0, b: { c: 2 } }
console.dir(copy); // { a: 1, b: { c: 2 } }
console.log(copy.b === foo.b) // true
复制代码
深拷贝
- 利用JSON将对象序列化为字符串,而后将其反序列化。
var obj = { a: 0, b: { c: 0 } };
var copy = JSON.parse(JSON.stringify(obj));
console.log(copy.a === obj.b) // false
复制代码
- 遗憾的是,此方法仅在源对象包含可序列化值类型且没有任何循环引用时才有效。
<!--函数丢失-->
var obj = { a: 0, b: { c: 0 }, d: function() {console.log('------>')} };
var copy = JSON.parse(JSON.stringify(obj));
console.log(copy) // {a: 0, b: {…}}
<!--日期对象将被转换为字符串化上以ISO格式打印-->
var obj = { a: 0, b: { c: 0 }, f: new Date() };
var copy = JSON.parse(JSON.stringify(obj));
console.log(copy) // {a: 0, b: {…}, f: "2018-12-07T08:11:48.210Z"}
复制代码
- NODE.JS中的深度复制
- 从8.0.0版开始,Node.js提供了与结构化克隆兼容的序列化API。
- 对于低于8.0.0的版本或更稳定的实现,能够使用lodash的cloneDeep方法,该方法也基于结构化克隆算法。
const v8 = require('v8');
const buf = v8.serialize({a: 'foo', b: new Date()});
const cloned = v8.deserialize(buf);
cloned.b.getMonth();
复制代码
小结
- 总而言之,在Javascript中复制对象的最佳算法在很大程度上取决于您要复制的对象的上下文和类型。虽然lodash是通用深层复制功能最安全的选择,咱们也能够动手写一个简单的适用日期拷贝的深度拷贝。
- 适用日期的深拷贝实现-示例
function deepClone(obj) {
var copy;
// Handle the 3 simple types, and null or undefined
if (null == obj || "object" != typeof obj) return obj;
// Handle Date
if (obj instanceof Date) {
copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
// Handle Array
if (obj instanceof Array) {
copy = [];
for (var i = 0, len = obj.length; i < len; i++) {
copy[i] = deepClone(obj[i]);
}
return copy;
}
// Handle Function
if (obj instanceof Function) {
copy = function() {
return obj.apply(this, arguments);
}
return copy;
}
// Handle Object
if (obj instanceof Object) {
copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = deepClone(obj[attr]);
}
return copy;
}
throw new Error("Unable to copy obj as type isn't supported " + obj.constructor.name);
}
复制代码
参考连接