本文主要记录一下深拷贝和浅拷贝的一些常用实现方式。
浅拷贝和深拷贝都只针对于引用数据类型,浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存;但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象;
区别:浅拷贝只复制对象的第一层属性、深拷贝可以对对象的属性进行递归复制;
浅拷贝
常用方式:
- Object.assign 方法
1 2 3 4
| var obj = { a: 1, b: 2 }; var obj1 = Object.assign({}, obj); obj1.a = 3; console.log(obj.a);
|
- for in 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| function simpleCopy(obj1) { var obj2 = Array.isArray(obj1) ? [] : {}; for (let i in obj1) { obj2[i] = obj1[i]; } return obj2; } var obj1 = { a: 1, b: 2, c: { d: 3, }, }; var obj2 = simpleCopy(obj1); obj2.a = 3; obj2.c.d = 4; console.log(obj1);
|
除了以上方法外,数组还有 slice, concat, 以及 ES6 提供的“…”运算符。当然这不是重点,重点是下面要说的深拷贝。
深拷贝
- 通过 JSON 的序列化和反序列化来实现:parse、stringify:
1 2 3 4 5 6
| var obj = { name: "张三", dog: { name: "小黑" } }; var newObj = JSON.parse(JSON.stringify(obj)); console.log(obj, newObj); console.log(obj == newObj); newObj.dog.name = "小花"; console.log(obj, newObj);
|
上面这种方式能满足我们日常业务需要,但是他有一个缺点,就是会忽略 undefined、任意的函数、symbol 值,因为 JSON 不支持这些数据类型;
- 递归调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
|
var class2type = {}; var toString = class2type.toString; var hasOwn = class2type.hasOwnProperty;
function isPlainObject(obj) { var proto, Ctor; if (!obj || toString.call(obj) !== "[object Object]") { return false; } proto = Object.getPrototypeOf(obj); if (!proto) { return true; } Ctor = hasOwn.call(proto, "constructor") && proto.constructor; return ( typeof Ctor === "function" && hasOwn.toString.call(Ctor) === hasOwn.toString.call(Object) ); }
function extend(target, source, deep) { for (var key in source) { if (deep && (isPlainObject(source[key]) || Array.isArray(source[key]))) { if (isPlainObject(source[key]) && !isPlainObject(target[key])) target[key] = {};
if (Array.isArray(source[key]) && !Array.isArray(target[key])) target[key] = []; extend(target[key], source[key], deep); } else if (source[key] !== undefined) target[key] = source[key]; } } var deepClone = function (target) { var deep, args = Array.prototype.slice.call(arguments, 1);
if (typeof target == "boolean") { deep = target; target = args.shift(); } args.forEach(function (arg) { extend(target, arg, deep); }); return target; }; var obj = {name:123,age:123,c:{d:3},e:{f:function(){}}}; var obj2 = deepClone(true,{}, obj); obj2.c.d = 12312; console.log(obj); console.log(obj2);
|