js對象淺拷貝和深拷貝詳解

1.淺拷貝jquery

拷貝就是把父對像的屬性,所有拷貝給子對象。數組

淺拷貝就是數據雙向改變。app

JavaScript存儲對象都是存地址的,因此淺拷貝會致使 obj1 和obj2 指向同一塊內存地址。改變了其中一方的內容,都是在原來的內存上作修改會致使拷貝對象和源對象都發生改變,而深拷貝是開闢一塊新的內存地址,將原對象的各個屬性逐個複製進去。對拷貝對象和源對象各自的操做互不影響。函數

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

1spa

2.net

3prototype

4插件

5指針

6

7

8

9

10

11

12

13

14

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;

 }

使用的時候,這樣寫:

?

1

2

3

var Doctor = extendCopy(Chinese);

Doctor.career = '醫生';

alert(Doctor.nation); // 中國

可是,這樣的拷貝有一個問題。那就是,若是父對象的屬性等於數組或另外一個對象,那麼實際上,子對象得到的只是一個內存地址,而不是真正拷貝,所以存在父對象被篡改的可能。

請看,如今給Chinese添加一個」出生地」屬性,它的值是一個數組。

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

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

var Doctor = extendCopy(Chinese);

而後,咱們爲Doctor的」出生地」添加一個城市:

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

看一下輸入結果

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

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

因此,extendCopy() 只是拷貝了基本類型的數據,咱們把這種拷貝叫作「淺拷貝」。

2.深拷貝

由於淺深拷有如此弊端因此咱們接下來看一下深拷貝

所謂」深拷貝」,就是可以實現真正意義上的數組和對象的拷貝。它的實現並不難,只要遞歸調用」淺拷貝」就好了。

?

1

2

3

4

5

6

7

8

9

10

11

12

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);

如今,給父對象加一個屬性,值爲數組。而後,在子對象上修改這個屬性:

?

1

2

3

4

5

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 
包含額外的屬性合併到第一個參數 

當咱們提供兩個或多個對象給$.extend(),對象的全部屬性都添加到目標對象(target參數)。

若是隻有一個參數提供給$.extend(),這意味着目標參數被省略。在這種狀況下,jQuery對象自己被默認爲目標對象。這樣,咱們能夠在jQuery的命名空間下添加新的功能。這對於插件開發者但願向 jQuery 中添加新函數時是頗有用的。

請記住,目標對象(第一個參數)將被修改,而且將經過$.extend()返回。然而,若是咱們想保留原對象,咱們能夠經過傳遞一個空對象做爲目標對象:

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

在默認狀況下,經過$.extend()合併操做不是遞歸的;若是第一個對象的屬性自己是一個對象或數組,那麼它將徹底用第二個對象相同的key重寫一個屬性。這些值不會被合併。能夠經過檢查下面例子中 banana 的值,就能夠了解這一點。然而,若是將 true 做爲該函數的第一個參數,那麼會在對象上進行遞歸的合併。

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

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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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. 採用遞歸方式合併兩個對象,並修改第一個對象。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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 對象。這是經常使用的插件開發模式。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

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中相等運算包括」==」,」===」全等,二者不一樣之處,沒必要多數,本篇文章咱們未來講述如何判斷兩個對象是否相等? 你可能會認爲,若是兩個對象有相同的屬性,以及它們的屬性有相同的值,那麼這兩個對象就相等。那麼下面咱們經過一個實例來論證下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

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)及普通對象經過指針指向的內存中的地址來作比較。看下面一個例子:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

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++)中值傳遞和引用傳遞的概念類似。 由於,若是你想判斷兩個對象是否相等,你必須清晰,你是想判斷兩個對象的屬性是否相同,仍是屬性對應的值是否相同,仍是怎樣?

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

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

相關文章
相關標籤/搜索