欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JS中實現(xiàn)淺拷貝和深拷貝的代碼詳解

 更新時間:2019年06月05日 11:19:17   作者:撩課學(xué)院  
JavaScript的變量中包含兩種類型的值:基本類型值 和 引用類型值,這篇文章主要介紹了JS中實現(xiàn)淺拷貝和深拷貝,需要的朋友可以參考下

(一)JS中基本類型和引用類型

JavaScript的變量中包含兩種類型的值:基本類型值 和 引用類型值,在內(nèi)存中的表現(xiàn)形式在于:前者是存儲在棧中的一些簡單的數(shù)據(jù)段,后者則是保存在堆內(nèi)存中的一個對象。

基本類型值

在JavaScript中基本數(shù)據(jù)類型有 String , Number , Undefined , Null , Boolean ,在ES6中,又定義了一種新的基本數(shù)據(jù)類型 Symbol ,所以一共有6種。

基本類型是按值訪問的,從一個變量復(fù)制基本類型的值到另一個變量后,這兩個變量的值是完全獨立的,即使一個變量改變了也不會影響到第二個變量。

var str1 = '撩課';
var str2 = str1;
str2 = 'itlike';
console.log(str2); //'itlike'
console.log(str1); //'撩課'

引用類型值

引用類型值是引用類型的實例,它是保存在堆內(nèi)存中的一個對象,引用類型是一種數(shù)據(jù)結(jié)構(gòu),最常用的是Object,Array,Function類型,此外還有Date,RegExp,Error等。

在ES6中提供了Set,Map2種新的數(shù)據(jù)結(jié)構(gòu)。

(二)JS中如何復(fù)制引用類型的

基本類型和引用類型賦值的差異化
舉個例子:在下面代碼中,只修改了obj1中的name屬性,卻同時改變了ob1和obj2中的name屬性。

var obj1 = {'name': '撩課'};
var obj2 = obj1;
obj2.name = '小撩';
console.log(obj1); // {'name': '撩課'}
console.log(obj2); // {'name': '撩課'}

當(dāng)變量復(fù)制引用類型值的時候,同樣和基本類型值一樣會將變量的值復(fù)制到新變量上,不同的是對于變量的值,它是一個指針,指向存儲在堆內(nèi)存中的對象。

因為,在JS中,堆內(nèi)存中的對象無法直接訪問,必須要訪問這個對象在堆內(nèi)存中的地址,然后再按照這個地址去獲得這個對象中的值。

(三)淺拷貝

在JS中,如果屬性是基本類型,拷貝的就是基本類型的值;如果屬性是引用類型,拷貝的就是內(nèi)存地址;所以如果其中一個對象改變了這個地址,就會影響到另一個對象。

下面是JavaScript提供的淺拷貝方法:

Object.assign

ES6中拷貝對象的方法,接受的第一個參數(shù)是拷貝的目標(biāo),剩下的參數(shù)是拷貝的源對象;

語法:Object.assign(target, ...sources)

var p = {
  'name': '張三',
};
var copyP = {};
Object.assign(copyP, p);
console.log(copyP);
console.log(p);

Object.assign是一個淺拷貝,它只是在根屬性(對象的第一層級)創(chuàng)建了一個新的對象,但是如果屬性的值是對象的話,只會拷貝一份相同的內(nèi)存地址。

擴(kuò)展運算符

利用擴(kuò)展運算符可以在構(gòu)造字面量對象時,進(jìn)行克隆或者屬性拷貝。語法如下:

var cloneObj = { ...obj };
var obj = {'name': '撩課', 'college': ['H5','JAVA','Python']}
var obj2 = {...obj};
obj.name='小撩';
//{'name': '小撩', 'college': ['H5','JAVA','Python']}
console.log(obj);
//{'name': '撩課', 'college': ['H5','JAVA','Python']}
console.log(obj2); 
obj.college.push('Go');
//{'name': '小撩', 'college': ['H5','JAVA','Python','Go']}
console.log(obj); 
//{'name': '小撩', 'college': ['H5','JAVA','Python','Go']}
console.log(obj2);

擴(kuò)展運算符和Object.assign()存在同樣的問題,對于值是對象的屬性無法完全拷貝成兩個不同對象;

但是如果屬性都是基本類型的值的話,使用擴(kuò)展運算符更加簡潔。

(四)深拷貝

淺拷貝只在根屬性上在堆內(nèi)存中創(chuàng)建了一個新的的對象,復(fù)制了基本類型的值,但是復(fù)雜數(shù)據(jù)類型也就是對象則是拷貝相同的地址。

而深拷貝則是將一個對象從內(nèi)存中完整的拷貝一份出來,從堆內(nèi)存中開辟一個新的區(qū)域存放新對象,且修改新對象不會影響原對象。

JSON.stringify

JSON.stringify()是目前開發(fā)過程中最常用的深拷貝方式,原理是把一個對象序列化成為一個JSON字符串,將對象的內(nèi)容轉(zhuǎn)換成字符串的形式再保存在內(nèi)存中,再用JSON.parse()反序列化將JSON字符串變成一個新的對象。

舉個例子:

var obj = {
  name: '撩課',
  age: 18,
  friends: ['小花', '小黑'],
  goodF: {
    name: '小撩',
    age: 19,
    address: '上海',
    pets: [{name: '土豆'}, {name: '馬鈴薯'}]},
  bir: new Date()
};

var newObj = JSON.parse(JSON.stringify(obj));
obj.goodF.pets[0].name = '旺財';
console.log(newObj);
console.log(obj);

使用JSON.stringify實現(xiàn)深拷貝有幾點要注意:

1)拷貝的對象的值中如果有函數(shù),undefined,symbol,經(jīng)過JSON.stringify()序列化后的JSON字符串中這個鍵值對會消失;

無法拷貝不可枚舉的屬性,無法拷貝對象的原型鏈
3)拷貝Date引用類型會變成字符串

4)拷貝RegExp引用類型會變成空對象

對象中含有NaN、Infinity和-Infinity,則序列化的結(jié)果會變成null

遞歸實現(xiàn)深拷貝

具體實現(xiàn)如下:

/**
 * 輔助函數(shù), 判定是否是對象
 * @param obj
 * @returns {boolean}
 */
function isObj(obj) {
  return obj instanceof Object;
}

/**
 * 深拷貝fromObj面的所有屬性/值, 到toObj對象里面
 * @param fromObj 拷貝對象
 * @param toObj  目標(biāo)對象
 */
function deepCopyObj2NewObj(fromObj, toObj) {
  for (var key in fromObj) {
    if(fromObj.hasOwnProperty(key)){
      var fromValue = fromObj[key];
      // 如果是值類型,那么就直接拷貝賦值
      if (!isObj(fromValue)) {
        toObj[key] = fromValue;
      } else {
        // 如果是引用類型,那么就再調(diào)用一次這個方法,
        // 去內(nèi)部拷貝這個對象的所有屬性
        // fromValue是什么類型, 創(chuàng)建一個該類型的空對象
        var tmpObj = new fromValue.constructor;

        // console.log(tmpObj);
        // debugger;
        deepCopyObj2NewObj(fromValue, tmpObj);
        toObj[key] = tmpObj;
      }
    }
  }
}

(五)總結(jié)

1)在日常開發(fā)中一般并不需要拷貝很多特殊的引用類型,深拷貝對象使用JSON.stringify是最直接和簡單的方法。

2)實現(xiàn)一個完整的深拷貝是非常復(fù)雜的,需要考慮到很多邊界情況。對于特殊的引用類型有拷貝需求的話,建議借助第三方完整的庫。

以上所述是小編給大家介紹的JS中實現(xiàn)淺拷貝和深拷貝的代碼詳解,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
如果你覺得本文對你有幫助,歡迎轉(zhuǎn)載,煩請注明出處,謝謝!

相關(guān)文章

  • js循環(huán)中使用正則失效異常的踩坑實戰(zhàn)

    js循環(huán)中使用正則失效異常的踩坑實戰(zhàn)

    這篇文章主要給大家介紹了關(guān)于js循環(huán)中使用正則失效異常的踩坑實戰(zhàn),文中通過實例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2023-05-05
  • 如何用js獲得當(dāng)前視頻播放的狀態(tài)

    如何用js獲得當(dāng)前視頻播放的狀態(tài)

    這篇文章主要給大家介紹了關(guān)于如何用js獲得當(dāng)前視頻播放狀態(tài)的相關(guān)資料,大家在日常應(yīng)用場景中可能會遇到這么一個情況,需要判斷用戶是否完整的觀看完了一部視頻,需要的朋友可以參考下
    2023-07-07
  • JS+CSS實現(xiàn)隨機(jī)點名(實例代碼)

    JS+CSS實現(xiàn)隨機(jī)點名(實例代碼)

    本文通過js html和cass代碼實現(xiàn)了隨機(jī)點名效果,代碼簡單易懂,非常不錯,具有一定的參考借鑒價值,需要的朋友參考下吧
    2019-11-11
  • JavaScript事件方法(實例講解)

    JavaScript事件方法(實例講解)

    下面小編就為大家?guī)硪黄狫avaScript事件方法(實例講解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • TypeScript中declare關(guān)鍵字的具體使用

    TypeScript中declare關(guān)鍵字的具體使用

    declare關(guān)鍵字用來告訴編譯器,某個類型是存在的,可以在當(dāng)前文件中使用,本文主要介紹了TypeScript中declare關(guān)鍵字的具體使用,感興趣的可以了解一下
    2023-10-10
  • JavaScript實現(xiàn)圖像壓縮的方法

    JavaScript實現(xiàn)圖像壓縮的方法

    使用 JavaScript 和 canvas 壓縮圖像可以使用 canvas 的 drawImage() 方法將圖像繪制到 canvas 上,然后使用 toDataURL() 方法將圖像轉(zhuǎn)換為 Data URL 形式,這篇文章主要介紹了JavaScript 圖像壓縮的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • uniapp使用uni.chooseLocation()打開地圖選擇位置詳解

    uniapp使用uni.chooseLocation()打開地圖選擇位置詳解

    這篇文章主要給大家介紹了關(guān)于uniapp使用uni.chooseLocation()打開地圖選擇位置的相關(guān)資料,因為最近在項目中遇到一個要用戶授權(quán)位置且可以用戶自己選擇位置的功能,需要的朋友可以參考下
    2023-06-06
  • 詳解CocosCreator系統(tǒng)事件是怎么產(chǎn)生及觸發(fā)的

    詳解CocosCreator系統(tǒng)事件是怎么產(chǎn)生及觸發(fā)的

    這篇文章主要介紹了CocosCreator系統(tǒng)事件是怎么產(chǎn)生及觸發(fā)的,雖然內(nèi)容不少,但是只要一點點抽絲剝繭,具體分析其內(nèi)容,就會豁然開朗
    2021-04-04
  • JavaScript實現(xiàn)音樂播放器

    JavaScript實現(xiàn)音樂播放器

    這篇文章主要為大家詳細(xì)介紹了JavaScript實現(xiàn)音樂播放器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • JavaScript實現(xiàn)登錄窗體

    JavaScript實現(xiàn)登錄窗體

    這篇文章主要為大家詳細(xì)介紹了JavaScript實現(xiàn)登錄窗體,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-06-06

最新評論