js深復制和淺復制

javaScript的變量類型

  • 基本類型:
    5種基本數(shù)據(jù)類型Undefined朝抖、NullBoolean谍珊、NumberString治宣,變量是直接按值存放的,存放在棧內(nèi)存中的簡單數(shù)據(jù)段砌滞,可以直接訪問侮邀。

  • 引用類型:
    存放在堆內(nèi)存中的對象,變量保存的是一個指針贝润,這個指針指向另一個位置绊茧。當需要訪問引用類型(如對象,數(shù)組等)的值時打掘,首先從棧中獲得該對象的地址指針华畏,然后再從堆內(nèi)存中取得所需的數(shù)據(jù)。

JavaScript存儲對象都是存地址的胧卤,所以淺拷貝會導致obj1obj2 指向同一塊內(nèi)存地址唯绍。改變了其中一方的內(nèi)容,都是在原來的內(nèi)存上做修改會導致拷貝對象和源對象都發(fā)生改變枝誊;而深拷貝是開辟一塊新的內(nèi)存地址况芒,將原對象的各個屬性逐個復制進去。對拷貝對象和源對象各自的操作互不影響叶撒。

淺復制的實現(xiàn)

  • 簡單的引用復制
   var data = {a: 1, b: 2};
   var c = data;
  • Object.assign()
    只會對第一層變量實現(xiàn)深復制绝骚;
    var data =  {
      a: 1,
      b: { f: { g: 1 } },
      c: [ 1, 2, 3 ]
    };
    
    var objData = Object.assign({}, data);
    
    console.log(objData === data); //false
    console.log(objData.b.f === data.b.f); //true
    
  • Array的slice和concat方法(與Object.assign()方法是一樣的)

    Arraysliceconcat方法不修改原數(shù)組,只會返回一個淺復制了原數(shù)組中的元素的一個新數(shù)組祠够。它看起來像是深拷貝压汪,而實際上它是淺拷貝。
    例子如下:

    var array = [1,2,3]; 
    var array_shallow = array; 
    var array_concat = array.concat(); 
    var array_slice = array.slice(0); 
    console.log(array === array_shallow); //true 
    console.log(array === array_slice); //false古瓤,“看起來”像深拷貝
    console.log(array === array_concat); //false止剖,“看起來”像深拷貝
    

    可以看出腺阳,concatslice返回的不同的數(shù)組實例,這與直接的引用復制是不同的穿香。

原數(shù)組的元素會按照下述規(guī)則拷貝:

  • 如果該元素是個對象引用 (不是實際的對象)亭引,slice 會拷貝這個對象引用到新的數(shù)組里。兩個對象引用都引用了同一個對象皮获。如果被引用的對象發(fā)生改變焙蚓,則新的和原來的數(shù)組中的這個元素也會發(fā)生改變。

     var array = [1, [1,2,3], {name:"array"}]; 
     var array_concat = array.concat();
     var array_slice = array.slice(0);
    
     array_concat[1][0] = 5;  //改變array_concat中數(shù)組元素的值 
    
     console.log(array[1]); //[5,2,3] 
     console.log(array_slice[1]); //[5,2,3] 
    
     array_slice[2].name = "array_slice"; //改變array_slice中對象元素的值 
    
     console.log(array[2].name); //array_slice
     console.log(array_concat[2].name); //array_slice
    

    可以看出Array的concatslice并不是真正的深復制洒宝,數(shù)組中的對象元素(Object,Array等)只是復制了引用购公。

  • 對于字符串、數(shù)字及布爾值來說(不是 String雁歌、Number 或者 Boolean 對象)宏浩,slice 會拷貝這些值到新的數(shù)組里。在別的數(shù)組里修改這些字符串或數(shù)字或是布爾值将宪,將不會影響另一個數(shù)組绘闷。

  • 如果向兩個數(shù)組任一中添加了新元素,則另一個不會受到影響较坛。

    var array = [1, 2, 3];
    
    var array_shallow = array;
    var array_concat = array.concat();
    var array_slice = array.slice(0);
    
    array.push(4);
    
    console.log(array_concat); //[1, 2, 3]
    

深復制的實現(xiàn)

JSON對象的parse和stringify

JSON對象是ES5中引入的新的類型(支持的瀏覽器為IE8+),JSON對象parse方法可以將JSON字符串反序列化成JS對象扒最,stringify方法可以將JS對象序列化成JSON字符串丑勤,借助這兩個方法,也可以實現(xiàn)對象的深拷貝吧趣。

var source = { name:"source", child:{ name:"child" } } 
var target = JSON.parse(JSON.stringify(source));
target.name = "target";  //改變target的name屬性

console.log(source.name); //source 
console.log(target.name); //target

target.child.name = "target child"; //改變target的child 
console.log(source.child.name); //child 
console.log(target.child.name); //target child
var source = { name:function(){console.log(1);}, child:{ name:"child" } } 
var target = JSON.parse(JSON.stringify(source));

console.log(target.name); //undefined
var source = { name:function(){console.log(1);}, child:new RegExp("e") }
var target = JSON.parse(JSON.stringify(source));

console.log(target.name); //undefined
console.log(target.child); //Object {}

這種方法使用較為簡單法竞,可以滿足基本的深拷貝需求,而且能夠處理JSON格式能表示的所有數(shù)據(jù)類型强挫,但是對于正則表達式類型岔霸、函數(shù)類型等無法進行深拷貝(而且會直接丟失相應的值)。

還有一點不好的地方是它會拋棄對象的constructor俯渤。也就是深拷貝之后呆细,不管這個對象原來的構造函數(shù)是什么,在深拷貝之后都會變成Object八匠。

如果對象中存在循環(huán)引用的情況也無法正確處理絮爷。

自定義方法實現(xiàn)深拷貝

function clone(data) {
    if (Array.isArray(data)) {
        let newArr = [];
        for (let i = 0; i < data.length; i++) {
            newArr[i] = clone(data[i]);
        }

        return newArr;
    } else if (data instanceof Object) {
        let obj = {};
        for (let key in data) {
            obj[key] = clone(data[[key]]);
        }
        return obj;
    }else {
        return data;
    }
}

var data =  {
    a: 1,
    b: { f: { g: 1 } },
    c: [ 1, 2, 3 ]
};

var objData = clone(data);
console.log(objData === data);  //false
console.log(objdata.b.f === data.b.f); //false
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市梨树,隨后出現(xiàn)的幾起案子坑夯,更是在濱河造成了極大的恐慌,老刑警劉巖抡四,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柜蜈,死亡現(xiàn)場離奇詭異仗谆,居然都是意外死亡,警方通過查閱死者的電腦和手機淑履,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門胸私,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鳖谈,你說我怎么就攤上這事岁疼。” “怎么了缆娃?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵捷绒,是天一觀的道長。 經(jīng)常有香客問我贯要,道長暖侨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任崇渗,我火速辦了婚禮字逗,結果婚禮上,老公的妹妹穿的比我還像新娘宅广。我一直安慰自己葫掉,他們只是感情好,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布跟狱。 她就那樣靜靜地躺著俭厚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪驶臊。 梳的紋絲不亂的頭發(fā)上挪挤,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天,我揣著相機與錄音关翎,去河邊找鬼扛门。 笑死,一個胖子當著我的面吹牛纵寝,可吹牛的內(nèi)容都是我干的论寨。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼店雅,長吁一口氣:“原來是場噩夢啊……” “哼政基!你這毒婦竟也來了?” 一聲冷哼從身側響起闹啦,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤沮明,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后窍奋,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體荐健,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡酱畅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了江场。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纺酸。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖址否,靈堂內(nèi)的尸體忽然破棺而出餐蔬,到底是詐尸還是另有隱情,我是刑警寧澤佑附,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布樊诺,位于F島的核電站,受9級特大地震影響音同,放射性物質(zhì)發(fā)生泄漏词爬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一权均、第九天 我趴在偏房一處隱蔽的房頂上張望顿膨。 院中可真熱鬧,春花似錦叽赊、人聲如沸恋沃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芽唇。三九已至,卻和暖如春取劫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背研侣。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工谱邪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人庶诡。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓惦银,卻偏偏與公主長得像,于是被迫代替她去往敵國和親末誓。 傳聞我的和親對象是個殘疾皇子扯俱,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容

  • js簡介 Js是一種基于事件和對象驅動的解釋性允粤、松散性的語言湖笨。 一切皆對象 javascript 布蘭登艾奇 ...
    塔庫納瑪哈哈閱讀 1,198評論 0 2
  • underscore 的源碼中,有很多地方用到了 Array.prototype.slice() 方法张漂,但是并沒有...
    theCoder閱讀 596評論 0 1
  • 單例模式 適用場景:可能會在場景中使用到對象晴玖,但只有一個實例读存,加載時并不主動創(chuàng)建为流,需要時才創(chuàng)建 最常見的單例模式,...
    Obeing閱讀 2,056評論 1 10
  • 國慶節(jié)當天我背起帆布包去往寧波让簿,看望剛在那邊安家的發(fā)小敬察,從小愛喚她“橘子”。 我是一個熱愛四處游走且懶的人尔当,促使我...
    z大雁閱讀 288評論 0 1
  • React Native 官方文檔 React Native 開源社區(qū) 【環(huán)境莲祸、組件、入門椭迎、進價等】 JavaSc...
    小黑Swift閱讀 309評論 0 2