什么是淺拷貝,什么是深拷貝?
什么是淺拷貝
關于淺拷貝的概念,我在網上看到一種說法,直接上代碼。
1.var person = {name: "Jason", age: 18, car: {brand: "Ferrari", type: "430"}};
2.var person1 = person; //他們認為這是淺拷貝
但是我個人認為,上面這個根本不涉及拷貝,只是一個簡單的引用賦值。以我的理解,淺拷貝應該是不考慮對象的引用類型的屬性,只對當前對象的所有成員進行拷貝,代碼如下:
function copy(obj){
var objCopy = {};
for(var key in obj){
objCopy[key] = obj[key];
}
return objCopy;
}
var person = {name: "Jason", age: 18, car: {brand: "Ferrari", type: "430"}};
var personCopy = copy(person);
上面這段代碼中,person對象擁有兩個基本類型的屬性name和age,一個引用類型的屬性car,當使用如上方法進行拷貝的時候,name和age屬性會被正常的拷貝,但是car屬性,只會進行引用的拷貝,這樣會導致拷貝出來的對象personCopy和person會共用一個car對象。這樣就是所謂的淺拷貝。
什么是深拷貝
深拷貝的就是在拷貝的時候,需要將當前要拷貝的對象內的所有引用類型的屬性進行完整的拷貝,也就是說拷貝出來的對象和原對象之間沒有任何數據是共享的,所有的東西都是自己獨占的一份。
如何實現深拷貝
實現深拷貝需要考慮如下幾個因素:
- 傳入的對象是使用對象字面量{}創建的對象還是由構造函數生成的對象-
- 如果對象是由構造函數創建出來的,那么是否要拷貝原型鏈上的屬性
- 如果要拷貝原型鏈上的屬性,那么如果原型鏈上存在多個同名的屬性,保留哪個
- 處理循環引用的問題
第三方庫實現深拷貝
我們可以通過$.extend()方法來完成深復制。值得慶幸的是,我們在jQuery中可以通過添加一個參數來實現遞歸extend。調用$.extend(true, {}, ...)就可以實現深復制,參考下面的例子:
var x = {
a: 1,
b: { f: { g: 1 } },
c: [ 1, 2, 3 ]
};
var y = $.extend({}, x), //shallow copy
z = $.extend(true, {}, x); //deep copy
y.b.f === x.b.f // true
z.b.f === x.b.f // false
但是jQuery的這個$.extend()方法,有弊端,什么弊端呢?我們看下面的例子:
var objA = {};
var objB = {};
objA.b = objB;
objB.a = objA;
$.extend(true,{},a);
//這個時候就出現異常了
//Uncaught RangeError: Maximum call stack size exceeded(…)
也就是說,jQuery中的$.extend()并沒有處理循環引用的問題。
使用JSON對象實現深拷貝
使用JSON全局對象的parse和stringify方法來實現深復制也算是一個簡單討巧的方法。
function jsonClone(obj) {
return JSON.parse(JSON.stringify(obj));
}
var clone = jsonClone({ a:1 });