何为深拷贝和浅拷贝
在 JS 中有一些基本类型像是Number
、String
、Boolean,
而对象就是像这样的东西{ name: 'Larry', skill: 'Node.js' },对象跟基本类型最大的不同就在于他们的传值方式。
基本类型是按值传递,像是这样:在修改a
时并不会改到b。
var a = 25; var b = a; b = 18; console.log(a);//25 console.log(b);//18
但对象就不同,对象传的是按引用传值
var obj1 = { a: 10, b: 20, c: 30 }; var obj2 = obj1; obj2.b = 100; console.log(obj1); // { a: 10, b: 100, c: 30 } <-- b 被改到了 console.log(obj2); // { a: 10, b: 100, c: 30 }
复制一份obj1
叫做obj2,
然后把obj2.b
改成100,
但却不小心改到obj1.b,
因为他们根本是同一个对象,这就是所谓的浅拷贝。
要避免这样的错误发生就要写成这样:
var obj1 = { a: 10, b: 20, c: 30 }; var obj2 = { a: obj1.a, b: obj1.b, c: obj1.c }; obj2.b = 100; console.log(obj1); // { a: 10, b: 20, c: 30 } <-- b 沒被改到 console.log(obj2); // { a: 10, b: 100, c: 30 }
这样就是深拷贝,不会改到原本的obj1。
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
如何实现深拷贝
浅拷贝的实现方式,也就是简单地复制而已,如何实现深拷贝呢?
手动复制
把一个对象的属性复制给另一个对象的属性
var obj1 = { a: 10, b: 20, c: 30 }; var obj2 = { a: obj1.a, b: obj1.b, c: obj1.c }; obj2.b = 100; console.log(obj1); // { a: 10, b: 20, c: 30 } <-- 沒被改到 console.log(obj2); // { a: 10, b: 100, c: 30 }
但这样很麻烦,要一个一个自己复制;而且这样的本质也不能算是 Deep Copy,因为对象里面也可能回事对象,如像下面这个状况:
var obj1 = { body: { a: 10 } }; var obj2 = { body: obj1.body }; obj2.body.a = 20; console.log(obj1); // { body: { a: 20 } } <-- 被改到了 console.log(obj2); // { body: { a: 20 } } console.log(obj1 === obj2); // false console.log(obj1.body === obj2.body); // true
虽然obj1
跟obj2
是不同对象,但他们会共享同一个obj1.body
,
所以修改obj2.body.a
时也会修改到旧的。
递归拷贝
function deepClone(initalObj, finalObj) { var obj = finalObj || {}; for (var i in initalObj) { if (typeof initalObj[i] === 'object') { obj[i] = (initalObj[i].constructor === Array) ? [] : {}; arguments.callee(initalObj[i], obj[i]); } else { obj[i] = initalObj[i]; } } return obj; } var str = {}; var obj = { a: {a: "hello", b: 21} }; deepClone(obj, str); console.log(str.a);
jquery
jquery 有提供一个$.extend
可以用来做 Deep Copy。
var $ = require('jquery'); var obj1 = { a: 1, b: { f: { g: 1 } }, c: [1, 2, 3] }; var obj2 = $.extend(true, {}, obj1); console.log(obj1.b.f === obj2.b.f); // false