1. 程式人生 > >Javascript深淺拷貝的原理

Javascript深淺拷貝的原理

在實際開發當中,我們經常會遇到要對物件進行深拷貝的情況。而且深拷貝這個問題在面試過程中也經常會遇到,下面就對本人在學習過程中的收穫,做以簡單的總結。

什麼是淺拷貝,什麼是深拷貝?

什麼是淺拷貝

關於淺拷貝的概念,我在網上看到一種說法,直接上程式碼。

12
var person = {name: "Jason", age: 18, car: {brand: "Ferrari", type: "430"}};var person1 = person;      //他們認為這是淺拷貝

但是我個人認為,上面這個根本不涉及拷貝,只是一個簡單的引用賦值。以我的理解,淺拷貝應該是不考慮物件的引用型別的屬性,只對當前物件的所有成員進行拷貝,程式碼如下:

12345678910
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物件擁有兩個基本型別的屬性nameage,一個引用型別的屬性car,當使用如上方法進行拷貝的時候,name

age屬性會被正常的拷貝,但是car屬性,只會進行引用的拷貝,這樣會導致拷貝出來的物件personCopyperson會共用一個car物件。這樣就是所謂的淺拷貝。

什麼是深拷貝

深拷貝的就是在拷貝的時候,需要將當前要拷貝的物件內的所有引用型別的屬性進行完整的拷貝,也就是說拷貝出來的物件和原物件之間沒有任何資料是共享的,所有的東西都是自己獨佔的一份。

如何實現深拷貝

實現深拷貝需要考慮的問題

實現深拷貝需要考慮如下幾個因素:

  • 傳入的物件是使用物件字面量{}建立的物件還是由建構函式生成的物件
  • 如果物件是由建構函式創建出來的,那麼是否要拷貝原型鏈上的屬性
  • 如果要拷貝原型鏈上的屬性,那麼如果原型鏈上存在多個同名的屬性,保留哪個
  • 處理迴圈引用的問題

第三方庫實現深拷貝

我們可以通過$.extend()</code>方法來完成深複製。值得慶幸的是,我們在<code>jQuery</code>中可以通過新增一個引數來實現遞迴<code>extend</code>。呼叫<code>$.extend(true, {}, ...)就可以實現深複製,參考下面的例子:

1234567891011
var x = {    a: 1,    b: { f: { g: 1 } },    c: [ 1, 2, 3 ]};var y = $.extend({}, x),          <span class="comment">//shallow copy</span></div><div class="line">    z = $.extend(true, {}, x);    //deep copyy.b.f === x.b.f       // truez.b.f === x.b.f       // false

但是jQuery的這個$.extend()</code>方法,有弊端,什麼弊端呢?我們看下面的例子:<br></p><figure class="highlight js"><table><tbody><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code" style="width: 647.5px;"><pre style="width: 647.5px;"><div class="line"><span class="keyword">var</span> objA = {};</div><div class="line"><span class="keyword">var</span> objB = {};</div><div class="line"></div><div class="line">objA.b = objB;</div><div class="line">objB.a = objA;</div><div class="line"></div><div class="line">$.extend(true,{},a);