首頁  >  文章  >  web前端  >  js物件淺拷貝和深拷貝詳解

js物件淺拷貝和深拷貝詳解

高洛峰
高洛峰原創
2017-01-03 15:57:121246瀏覽

本文為大家分享了JavaScript物件的淺拷貝和深拷貝程式碼,供大家參考,具體內容如下

1.淺拷貝

拷貝就是把父對像的屬性,全部拷貝給子物件。

下面這個函數,就是在做拷貝:

var Chinese = {
  nation:'中国'
}
var Doctor = {
  career:'医生'
}  
function extendCopy(p) {
    var c = {};
    for (var i in p) { 
      c[i] = p[i];
    }
    c.uber = p;
    return c;
 }

使用的時候,這樣寫:

var Doctor = extendCopy(Chinese);
Doctor.career = '医生';
alert(Doctor.nation); // 中国

但是,這樣的拷貝有一個問題。那就是,如果父對象的屬性等於數組或另一個對象,那麼實際上,子對象獲得的只是一個記憶體地址,而不是真正拷貝,因此存在父對像被篡改的可能。

請看,現在給Chinese加上一個」出生地」屬性,它的值是一個陣列。

Chinese.birthPlaces = ['北京','上海','香港'];

透過extendCopy()函數,Doctor繼承了Chinese。

var Doctor = extendCopy(Chinese);

然後,我們為Doctor的」出生地」增加一個城市:

Doctor.birthPlaces.push('廈門');

Doctor.birthPlaces.push('廈門');

Doctor.birthPlaces.push('廈門');

看一下輸入結果.birthPlaces); //北京, 上海, 香港, 廈門

alert(Chinese.birthPlaces); //北京, 上海, 香港, 廈門

結果是兩個的出生地都被改了。

所以,extendCopy() 只是拷貝了基本類型的數據,我們把這種拷貝叫做「淺拷貝」。

2.深拷貝

因為淺深拷貝如此弊端所以我們接下來看一下深拷貝

所謂”深拷貝”,就是能夠實現真正意義上的數組和對象的拷貝。它的實作並不難,只要遞歸呼叫」淺拷貝」就行了。

function deepCopy(p, c) {
    var c = c || {};
    for (var i in p) {
      if (typeof p[i] === 'object') {
        c[i] = (p[i].constructor === Array) ? [] : {};
        deepCopy(p[i], c[i]);
      } else {
         c[i] = p[i];
      }
    }
    return c;
  }

看一下使用方法:

var Doctor = deepCopy(Chinese);

現在,為父物件加一個屬性,值為陣列。然後,在子物件上修改這個屬性:

Chinese.birthPlaces = ['北京','上海','香港'];
Doctor.birthPlaces.push('厦门');
 
alert(Doctor.birthPlaces); //北京, 上海, 香港, 厦门
alert(Chinese.birthPlaces); //北京, 上海, 香港

這樣就完成了拷貝;

$.extend()

jquery 中$.extend()如同。

$.extend( [deep ], target, object1 [, objectN ] )



 •deep 
類型: Boolean 
如果是true,合併成為遞歸(又叫做深拷貝)。
 •target 
類型: Object 
物件擴充。這將接收新的屬性。
 •object1 
類型: Object 
一個對象,它包含額外的屬性合併到第一個參數.
 •objectN 
類型: Object 

包含額外的屬性合併到第一個參數 

類型: Object 

包含額外的屬性合併到第一個參數 

多個物件給$.extend(),物件的所有屬性都會加入目標物件(target參數)。

如果只有一個參數提供給$.extend(),這表示目標參數被省略。在這種情況下,jQuery物件本身被預設為目標物件。這樣,我們可以在jQuery的命名空間下加入新的功能。這對於外掛程式開發者希望在 jQuery 中新增函數時是很有用的。

請記住,目標物件(第一個參數)將被修改,並且將透過$.extend()傳回。然而,如果我們想要保留原對象,我們可以透過傳遞一個空對像作為目標對象:

var object = $.extend({}, object1, object2);

在預設情況下,透過$.extend()合併操作不是遞歸的;如果第一個物件的屬性本身是一個物件或數組,那麼它將完全用第二個物件相同的key重寫一個屬性。這些值不會被合併。可以透過檢查下面例子中 banana 的值,就可以了解這一點。然而,如果將 true 作為該函數的第一個參數,那麼就會在物件上進行遞歸的合併。

警告:不支援第一個參數傳遞 false 。

1. 合併兩個對象,並修改第一個對象。

var object1 = {
 apple: 0,
 banana: { weight: 52, price: 100 },
 cherry: 97
};
var object2 = {
 banana: { price: 200 },
 durian: 100
};
 
// Merge object2 into object1
$.extend( object1, object2 );
 
// Assuming JSON.stringify - not available in IE<8
console.log( JSON.stringify( object1 ) );
//{"apple":0,"banana":{"price":200},"cherry":97,"durian":100}

2. 採用遞歸方式合併兩個對象,並修改第一個對象。

var object1 = {
 apple: 0,
 banana: { weight: 52, price: 100 },
 cherry: 97
};
var object2 = {
 banana: { price: 200 },
 durian: 100
};
 
// Merge object2 into object1, recursively
$.extend( true, object1, object2 );
 
// Assuming JSON.stringify - not available in IE<8
console.log( JSON.stringify( object1 ) );
//{"apple":0,"banana":{"weight":52,"price":200},"cherry":97,"durian":100}

3. 合併 defaults 和 options 對象,並且不修改 defaults 對象。這是常用的插件開發模式。

var defaults = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };
 
// Merge defaults and options, without modifying defaults
var settings = $.extend( {}, defaults, options );
 
 
console.log(JSON.stringify( defaults ));
console.log(JSON.stringify( options ));
console.log(JSON.stringify( settings ));
//defaults -- {"validate":false,"limit":5,"name":"foo"}
//options -- {"validate":true,"name":"bar"}
//settings -- {"validate":true,"limit":5,"name":"bar"}

Javascript 判斷物件是否相等

在Javascript中相等運算包括”==”,”===”全等,兩者不同之處,不必多數,本篇文章我們將來講述如何判斷兩個對像是否相等? 你可能會認為,如果兩個物件有相同的屬性,以及它們的屬性有相同的值,那麼這兩個物件就相等。那麼下面我們透過一個實例來論證下:

var obj1 = {
  name: "Benjamin",
  sex : "male"
}
 
var obj2 = {
  name: "Benjamin",
  sex : "male"
}
 
//Outputs: false
console.log(obj1 == obj2);
 
//Outputs: false
console.log(obj1 === obj2);

透過上面的例子可以看到,無論使用”==”還是”===”,都回傳false。主要原因是基本型別string,number透過值來比較,而物件(Date,Array)及一般物件則透過指標所指向的記憶體中的位址來做比較。看下面一個例子:

var obj1 = {
  name: "Benjamin",
  sex : "male"
};
 
var obj2 = {
  name: "Benjamin",
  sex : "male"
};
 
var obj3 = obj1;
 
//Outputs: true
console.log(obj1 == obj3);
 
//Outputs: true
console.log(obj1 === obj3);
 
//Outputs: false
console.log(obj2 == obj3);
 
//Outputs: false
console.log(obj2 === obj3);

上例回傳true,是因為obj1和ob3的指標指向了記憶體中的同一個位址。和物件導向的語言(Java/C++)中值傳遞和參考傳遞的概念相似。 因為,如果你想判斷兩個物件是否相等,你必須清晰,你是想判斷兩個物件的屬性是否相同,還是屬性對應的值是否相同,還是怎樣?

function person(name) { 
  this.name=name; 
} 
 
var p1 = new person("p1"); 
var p2 = new person("p2"); 
 
console.log(p1 == p2); //false 
 
person.prototype.sayHi = function() { 
  // do sayHi here 
} 
 
console.log(p1.sayHi() == p2.sayHi()); //true 
console.log(p1.sayHi() === p2.sayHi()); //true

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支PHP中文網。 🎜🎜更多js物件淺拷貝和深拷貝詳解相關文章請關注PHP中文網! 🎜
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn