前端基礎(chǔ)進(jìn)階(二): 深淺拷貝

深拷貝與淺拷貝

基本類型的拷貝

先來看一段非常經(jīng)典的代碼

var a = 1;
var b = a;
a = 200;
console.log(a);      //200
console.log(b);      //1

我們應(yīng)該知道基本類型“按值傳遞”,引用類型“按引用傳遞”,數(shù)值作為基本類型是保存在棧內(nèi)存中,可以直接拿來用的,賦值是什么那么之后就一直是什么,不會(huì)受到傳遞元素的改變帶來的影響,所以這里就不難理解上面的代碼得到的值的原因了。

引用類型的拷貝

簡(jiǎn)單說,引用類型是生成一個(gè)指針保存的堆內(nèi)存中,當(dāng)給引用類型賦值時(shí),我們寫的內(nèi)容是在棧內(nèi)存中,也就是說我們拿到的其實(shí)是一個(gè)指針(不會(huì)直接拿到棧內(nèi)存中的內(nèi)容)。這個(gè)指針是指向棧內(nèi)存中這個(gè)引用類型的代碼。

淺拷貝針對(duì)對(duì)象中的基本類型的值生效,但是對(duì)引用類型中還有引用類型的情況就會(huì)失效。
所謂的深淺拷貝是相對(duì)與typeof === 'object' 而言的,數(shù)組是用堆對(duì)應(yīng)保存的。
淺拷貝:拷貝了對(duì)象的存放地址,只是指向相同而已 (只解決了第一層,對(duì)象中還有對(duì)象就不適用了)
深拷貝:完全復(fù)制了一個(gè)獨(dú)立的個(gè)體

  • 淺拷貝方法:(直接 =,Object.assign...大部分都是淺拷貝)

=

 let arr1 = [1,3,5];
 let arr2 = arr1;
 arr1[0] = 10;
 console.log(arr2) // [10,3,5]
var obj1 = {
       name: '張三'
}

var obj2 = obj1;
obj2.name = '李四';

console.log(obj1.name); // '李四'

Object.assign

var obj1 = {
       name: '張三'
}

var obj2 = Object.assign({}, obj1);
obj2.name = '李四';
console.log(obj1.name);  // '張三'

至此,淺拷貝成功,但存在兼容性問題,比如低端的安卓機(jī)等,這個(gè)需要注意。但細(xì)心的朋友肯定會(huì)再做一個(gè)測(cè)試,如下:

var obj1 = {
       name: '張三',
       friends: {
          name: '劉備',
          age: 33
      }
}

var obj2 = Object.assign({}, obj1);
obj2.name = '李四';
obj2.friends.name = '關(guān)羽';
console.log(obj1.name);  // '張三'
console.log(obj1.friends.name);  // '關(guān)羽'

是的,到這一步,我們失敗了,對(duì)象中嵌套對(duì)象時(shí),Object.assign()只能拷貝一層,那如何解決呢?其實(shí)就要用到深拷貝的方法了:

var obj1 = {
       name: '張三',
       friends: {
          name: '劉備',
          age: 33
      }
}

var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.name = '李四';
obj2.friends.name = '關(guān)羽';
console.log(obj1.name);  // '張三'
console.log(obj1.friends.name);  // '劉備'
  • 深拷貝方法:
    Json.parse(Json.stringify())
var obj1 = {
       name: '張三',
       friends: {
          name: '劉備',
          age: 33
      }
}

var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.name = '李四';
obj2.friends.name = '關(guān)羽';
console.log(obj1.name);  // '張三'
console.log(obj1.friends.name);  // '劉備'

$.extend
...運(yùn)算符

 let arr = [1,3,5];
 let arr1 = [...arr];

返回新數(shù)組方法 slice() 、 contat()、 map()

  let arr1 = [2,5,7];
  let arr2 = arr1.slice(0);
  let arr3 = arr1.contat();
  let arr4 = arr1.map(x => x);
  arr2[0] = 4;
 arr1[0] = 99;
console.log(arr1,arr2) // [99,5,7]  [4,5,7] 

for-in連原型鏈也一并復(fù)制的方法

 let arr = [1,3,5];
 let arr2 = [] ;
 for(var key in arr) {
  arr2[key] = arr[key]
}

封裝方法

   /**
     * 判斷對(duì)象類型
     * @param {Object} object
     * @return {String} object type
     */
    getType(object) {
        var toString = Object.prototype.toString;
        var map = {
            '[object Boolean]': 'boolean',
            '[object Number]': 'number',
            '[object String]': 'string',
            '[object Function]': 'function',
            '[object Array]': 'array',
            '[object Date]': 'date',
            '[object RegExp]': 'regExp',
            '[object Undefined]': 'undefined',
            '[object Null]': 'null',
            '[object Object]': 'object'
        };
        if (object instanceof Element) {
            return 'element';
        }
        return map[toString.call(object)];
    },
       /**
     * 對(duì)象的深度拷貝
     * @param data 需要拷貝的元數(shù)據(jù)
     * @return {any} 返回拷貝后的新數(shù)據(jù)
     */
    deepClone(data) {
        const type = this.getType(data);
        let obj;

        if (type === 'array') {
            obj = [];
        } else if (type === 'object') {
            obj = {};
        } else {
            //不再具有下一層次
            return data;
        }
        if (type === 'array') {
            for (let i = 0, len = data.length; i < len; i++) {
                obj.push(this.deepClone(data[i]));
            }
        } else if (type === 'object') {
            for (let key in data) {
                obj[key] = this.deepClone(data[key]);
            }
        }

        const constructor = data.constructor;
        if (constructor) {
            return Object.assign(new constructor(), obj);
        }
        return obj;
    },
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 307、setValue:forKey和setObject:forKey的區(qū)別是什么? 答:1, setObjec...
    AlanGe閱讀 1,708評(píng)論 0 1
  • 37.cocoa內(nèi)存管理規(guī)則 1)當(dāng)你使用new,alloc或copy方法創(chuàng)建一個(gè)對(duì)象時(shí),該對(duì)象的保留計(jì)數(shù)器值為1...
    如風(fēng)家的秘密閱讀 954評(píng)論 0 4
  • 最全的iOS面試題及答案 iOS面試小貼士 ———————————————回答好下面的足夠了-----------...
    zweic閱讀 2,796評(píng)論 0 73
  • 多線程、特別是NSOperation 和 GCD 的內(nèi)部原理。運(yùn)行時(shí)機(jī)制的原理和運(yùn)用場(chǎng)景。SDWebImage的原...
    LZM輪回閱讀 2,108評(píng)論 0 12
  • 2019年5月14日 星期二 唉,昨天晚上睡得真的很爛,才凌晨一點(diǎn)就被熱醒了…… 今天肚子還是不舒服...
    浪漫的晚霞閱讀 743評(píng)論 0 0

友情鏈接更多精彩內(nèi)容