成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

javascript的深拷貝VS淺拷貝

Nekron / 2577人閱讀

摘要:深拷貝淺拷貝本文主要對(duì)深拷貝淺拷貝的解釋及實(shí)現(xiàn)做一下簡單記錄。之所以會(huì)有深拷貝與淺拷貝之分,是因?yàn)椴煌瑪?shù)據(jù)類型的數(shù)據(jù)在內(nèi)存中的存儲(chǔ)區(qū)域不一樣。但注意,只能做一層屬性的淺拷貝。

深拷貝VS淺拷貝

本文主要對(duì)深拷貝&淺拷貝的解釋及實(shí)現(xiàn)做一下簡單記錄。原文鏈接,歡迎star。

之所以會(huì)有深拷貝與淺拷貝之分,是因?yàn)椴煌瑪?shù)據(jù)類型的數(shù)據(jù)在內(nèi)存中的存儲(chǔ)區(qū)域不一樣。

堆和棧是計(jì)算機(jī)中劃分出來用來存儲(chǔ)的區(qū)域,其中堆(heap)則是動(dòng)態(tài)分配的內(nèi)存,大小不定也不會(huì)自動(dòng)釋放;而棧(stack)為自動(dòng)分配的內(nèi)存空間,它由系統(tǒng)自動(dòng)釋放。存放在棧內(nèi)存中的簡單數(shù)據(jù)段,數(shù)據(jù)大小確定,內(nèi)存空間大小可以分配,是直接按值存放的,所以可以直接訪問。

眾所周知,JavaScript中的數(shù)據(jù)分為(基本類型和引用類型)。五種基本類型(boolean,number,undefined,null,string,)的數(shù)據(jù)的原始值是大小確定不可變的,所以放在棧內(nèi)存中;而引用類型(object)是放在堆內(nèi)存中的,對(duì)應(yīng)賦值的變量只是一個(gè)存放在棧內(nèi)存中的指針,也就是一個(gè)指向引用類型存放在堆內(nèi)存中的地址。

引用類型比較與基本類型比較的區(qū)別

引用類型是引用的比較,例如

// a與b是兩個(gè)引用類型,但其指針指向的是兩個(gè)不同的引用
let a = [1,2,3];
let b = [1,2,3];
a===b; //false

// 引用類型的賦值操作,b的指針也是指向與a同樣的引用
let a = [1,2,3];
let b = a;
a===b; //true

而基本類型間的比較是值的比較,例如

let a = 1;
let b = 1;
a===b; //true

let a = 1;
let b = a;
a===b; //true
賦值操作:傳值與傳址的區(qū)別

在對(duì)基本類型進(jìn)行賦值操作的時(shí)候?qū)嶋H是傳值,即在棧內(nèi)存中新開一個(gè)區(qū)域給新的變量,然后再把值賦給它。所以基本類型賦值的變量是兩個(gè)互相獨(dú)立變量。

let a = 10;
let b = a;
b++;
console.log(a); //10
console.log(b); //11

而引用類型的賦值操作是傳址,只是在棧內(nèi)存中新增了一個(gè)變量,同時(shí)賦值給這個(gè)變量的只是保存在堆內(nèi)存中對(duì)象的地址,也就是指針的指向。因此這兩個(gè)變量的指針指向同一個(gè)地址,相互操作也就會(huì)有影響。

let a = {};
let b = a;

a.name = "slevin";
console.log(b.name); //"slevin"
console.log(a.name); //"slevin"
console.log(a===b); //true

需要注意的是,引用類型的賦值并不算是淺拷貝,因?yàn)橘x值操作只相當(dāng)于是引用,兩個(gè)變量還是指向同一對(duì)象,任何一方改變了都會(huì)影響到另一方;但淺拷貝出來的變量與源變量已經(jīng)不同,在不包含子對(duì)象的情況下(此情況即為深拷貝),一方改變不會(huì)影響到另一方。如下賦值操作:

let a = {};
let b = a;

b.name = "slevin";
console.log(a.name); //"slevin";對(duì)b操作影響到了a
console.log(a===b); //true;因?yàn)閮烧咧赶蛲粋€(gè)對(duì)象
淺拷貝實(shí)現(xiàn)方法

自定義實(shí)現(xiàn)方法:

// 淺拷貝的方法
function shallowCopy(srcObj) {
  let copy = {};
  for (let key in srcObj) {
      //只拷貝自身的屬性,__proto__上繼承來的屬性不做拷貝,也可去掉這個(gè)限制
      if (srcObj.hasOwnProperty(key)) {
          copy[key] = srcObj[key];
      }
  }
  return copy;
}

let obj = {
  name: "slevin",
  age: 18,
  language: {
      "english": "good",
      "mandarin": "wonderful",
  }
}

let copy = shallowCopy(obj);
copy.age = 28;

console.log(obj.age); // 18; 并沒有改變?cè)磳?duì)象
console.log(obj === copy); //false;兩者指向不是同一個(gè)對(duì)象

利用Object.assign(target,...sources)可將一個(gè)或多個(gè)源對(duì)象上可枚舉屬性的值復(fù)制到目標(biāo)對(duì)象,并返回目標(biāo)對(duì)象。但注意,只能做一層屬性的淺拷貝。

let obj = {
  name: "slevin",
  age: 18,
  language: {
      english: "good",
      mandarin: "wonderful",
      test: [1, 2, 3]
  },
  fn:function(){
      console.log("this:",this.name);
  }
}

let copy = Object.assign({},obj);
//不會(huì)改變?cè)磳?duì)象
copy.age = 22;
//會(huì)改變?cè)磳?duì)象
copy.language.english = "bad";
console.log("copy===obj:",copy===obj);//false
console.log("copy:",copy);
console.log("obj:",obj);

對(duì)于數(shù)組來說,也可以使用Array.prototype.slice()方法和Array.prototype.concact()方法

let obj = [1,2,["a","b","c"]]
let copy = obj.slice();
// 不會(huì)改變?cè)磳?duì)象
copy[0]=111;
// 會(huì)改變?cè)磳?duì)象
copy[2][0]="aaa";
console.log("copy===obj:",copy===obj);//false
console.log("copy:",copy);
console.log("obj:",obj);

深拷貝及實(shí)現(xiàn)方法

簡單來說,深拷貝就是把對(duì)象以及對(duì)象的子對(duì)象進(jìn)行拷貝。因?yàn)闇\拷貝只復(fù)制了一層對(duì)象的屬性,而如果對(duì)象的數(shù)值也為引用類型,那么拷貝過來依然是個(gè)引用地址,在拷貝對(duì)象上對(duì)子對(duì)象的值進(jìn)行操作會(huì)改變?cè)紨?shù)據(jù)中的值。

例如上面obj淺拷貝得到copy對(duì)象,如果在copy對(duì)象上改變子對(duì)象copy.language上的屬性值,會(huì)影響到源對(duì)象obj

copy.language.english = "bad";
copy.language.mandarin = "bad";
console.log(obj.language); // {"english": "bad","mandarin": "bad",}

那么如何深拷貝呢?思路就是遞歸調(diào)用剛剛的淺拷貝,遍歷所有值為引用類型的屬性,然后依次賦值給另外一個(gè)對(duì)象即可。

方法一,自定義實(shí)現(xiàn):

/**將源對(duì)象source深度合并到目標(biāo)對(duì)象target上

source 源對(duì)象

target 目標(biāo)對(duì)象,默認(rèn){}

deep 是否深度合并,默認(rèn)true

*/

function deepCopy (source,target={},deep=true) {
  for (let key in source){
      // 深拷貝,而且只拷貝自身屬性.(默認(rèn)傳入的source為對(duì)象)
      if (deep && source.hasOwnProperty(key)){
          if (typeof(source[key])==="object"){
              // // source[key] 是對(duì)象,而 target[key] 不是對(duì)象, 則 target[key] = {} 初始化一下,否則遞歸會(huì)出錯(cuò)的
              // if (!(target[key] instanceof Object) && (source[key] instanceof Object)){
              // target[key] = {};
              // }
              // // source[key] 是數(shù)組,而 target[key] 不是數(shù)組,則 target[key] = [] 初始化一下,否則遞歸會(huì)出錯(cuò)的
              // if (!Array.isArray(target[key]) && Array.isArray(source[key])) {
              // target[key] = [];
              // }
              // 上面的代碼可以簡化為以下:
              target[key] = Array.isArray(source[key]) ? [] : {};

              // 遞歸執(zhí)行拷貝
              deepCopy(source[key],target[key],true);
          } else {
              target[key] = source[key];
          }
      }
  }
  return target;
}


let obj = {
  name: "slevin",
  age: 18,
  language: {
      english: "good",
      mandarin: "wonderful",
      test:[1,2,3]
  }
}
let copy = deepCopy(obj);
copy.language.test[0] = 111;

console.log("copy:",copy); //111 改變目標(biāo)對(duì)象的子對(duì)象屬性值
console.log("obj:",obj); //1 對(duì)應(yīng)源對(duì)象上沒有改變

利用JSON.parse(JSON.stringify(copyObj))方法

let obj = {
  name: "slevin",
  age: 18,
  language: {
      english: "good",
      mandarin: "wonderful",
      test: [1, 2, 3]
  }
}
let copy = JSON.parse(JSON.stringify(obj))
copy.language.test[0]=111;

console.log("copy===obj:",copy===obj);//false
console.log("copy.language.test[0]:",copy.language.test[0]);//111
console.log("obj.language.test[0]:",obj.language.test[0]);//1

但要注意,此方法有兩個(gè)缺點(diǎn)

如果源對(duì)象屬性值有函數(shù),無法拷貝下來

無法拷貝源對(duì)象原型鏈上的屬性和方法

let obj = {
  name: "slevin",
  age: 18,
  language: {
      english: "good",
      mandarin: "wonderful",
      test: [1, 2, 3]
  },
  fn:function(){
      console.log("this:",this.name);
  }
}
let copy = JSON.parse(JSON.stringify(obj));
console.log("copy===obj:",copy===obj);//false
console.log("obj.fn:",obj.fn); //fn(){}...
console.log("copy.fn:",copy.fn); //undefined

最后,再補(bǔ)一張引用類型的賦值操作、淺拷貝深拷貝對(duì)比圖,加深印象

參考資料

js 深拷貝 vs 淺拷貝

深拷貝與淺拷貝的區(qū)別,實(shí)現(xiàn)深拷貝的幾種方法

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/101561.html

相關(guān)文章

  • JavaScript·隨記 深拷貝 vs. 拷貝

    摘要:而在這個(gè)運(yùn)算符的相關(guān)用例中,往往會(huì)涉及到其他知識(shí)點(diǎn),深拷貝和淺拷貝就是其中之一。即對(duì)象的淺拷貝會(huì)對(duì)主對(duì)象的值進(jìn)行拷貝,而該值有可能是一個(gè)指針,指向內(nèi)存中的同一個(gè)對(duì)象。,可以看到深拷貝和淺拷貝是對(duì)復(fù)制引用類型變量而言的。 在ES6的系列文章中,基本都會(huì)提到Spread——擴(kuò)展運(yùn)算符(...)。而在這個(gè)運(yùn)算符的相關(guān)用例中,往往會(huì)涉及到其他知識(shí)點(diǎn),深拷貝和淺拷貝就是其中之一。 背景知識(shí) 在討...

    RyanQ 評(píng)論0 收藏0
  • javascript對(duì)象的拷貝、深拷貝和Object.assign方法

    摘要:對(duì)象的淺拷貝淺拷貝是對(duì)象共用一個(gè)內(nèi)存地址,對(duì)象的變化相互影響。這是特別值得注意的地方。和能正確處理的對(duì)象只有等能夠被表示的數(shù)據(jù)結(jié)構(gòu),因此函數(shù)這種不能被表示的類型將不能被正確處理。 對(duì)象的淺拷貝: 淺拷貝是對(duì)象共用一個(gè)內(nèi)存地址,對(duì)象的變化相互影響。比如常見的賦值引用就是淺拷貝: let srcObj = {name: lilei, age: 20}; let copyObj = srcO...

    lixiang 評(píng)論0 收藏0
  • JavaScript的深拷貝拷貝

    摘要:針對(duì)于的對(duì)象和數(shù)組數(shù)組也是對(duì)象淺拷貝只是引用,內(nèi)存不變而深拷貝就是遞歸賦值。而淺拷貝會(huì)影響還可以用一句簡單的代碼實(shí)現(xiàn)上面的深拷貝 針對(duì)于JavaScript的對(duì)象和數(shù)組(數(shù)組也是對(duì)象)淺拷貝只是引用,內(nèi)存不變;而深拷貝就是遞歸賦值。 深拷貝是不同內(nèi)存,相互獨(dú)立。而淺拷貝會(huì)影響 var arr = [1,2,3],arr2=[]; for(var i=0;i

    GHOST_349178 評(píng)論0 收藏0
  • JS 中的深拷貝拷貝

    摘要:什么是深拷貝淺拷貝見名知義,無論是深拷貝還是淺拷貝,都是的問題。使用如下以上就是關(guān)于中的深拷貝與淺拷貝的知識(shí)和如何進(jìn)行深拷貝的知識(shí)了,如果有錯(cuò)或者有其他方式的話,歡迎在下面留言評(píng)論啦 前言 最近在寫項(xiàng)目的時(shí)候涉及到一些父子組件傳遞個(gè)對(duì)象或者數(shù)組通信啥的,或者是直接復(fù)制添加對(duì)象啥的,直接使用賦值的時(shí)候總會(huì)出錯(cuò)。一查原來是淺拷貝的問題,就從網(wǎng)上找了點(diǎn)資料,匯總到這里來了。 1 什么是深拷貝...

    ztyzz 評(píng)論0 收藏0
  • 低門檻徹底理解JavaScript的深拷貝拷貝

    摘要:案例中的賦值就是典型的淺拷貝,并且深拷貝與淺拷貝的概念只存在于引用類型。修改修改經(jīng)測(cè)試,也只能實(shí)現(xiàn)一維對(duì)象的深拷貝。經(jīng)過驗(yàn)證,我們發(fā)現(xiàn)提供的自有方法并不能徹底解決的深拷貝問題。 在說深拷貝與淺拷貝前,我們先看兩個(gè)簡單的案例: //案例1 var num1 = 1, num2 = num1; console.log(num1) //1 console.log(num2) //1 num...

    wind3110991 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<