Javascript中的淺拷貝和深拷貝

在 JavaScript 中,對于ObjectArray這類引用類型值弧可,當從一個變量向另一個變量復制引用類型值時,這個值的副本其實是一個指針劣欢,兩個變量指向同一個堆對象棕诵,改變其中一個變量,另一個也會受到影響凿将。

這種拷貝分為兩種情況:拷貝引用和拷貝實例校套,也就是我們說的淺拷貝和深拷貝。

淺拷貝(shallow copy)

拷貝原對象的引用牧抵,這是最簡單的淺拷貝笛匙。

// 對象
var o1 = {a: 1};
var o2 = o1;

console.log(o1 === o2); // =>true
o2.a = 2;
console.log(o1.a); // => 2

// 數(shù)組
var o1 = [1,2,3];
var o2 = o1;

console.log(o1 === o2); // => true
o2.push(4);
console.log(o1); // => [1,2,3,4]

拷貝原對象的實例,但是對其內部的引用類型值犀变,拷貝的是其引用妹孙,常用的就是如jquey中的$.extend({}, obj); Array.prototype.slice()Array.prototype.concat()都會返回一個數(shù)組或者對象的淺拷貝,舉個例子:

var o1 = ['darko', {age: 22}];
var o2 = o1.slice(); // 根據(jù)Array.prototype.slice()的特性获枝,這里會返回一個o1的淺拷貝對象

console.log(o1 === o2); // => false蠢正,說明o2拷貝的是o1的一個實例

o2[0] = 'lee';
console.log(o1[0]); // => "darko" o1和o2內部包含的基本類型值,復制的是其實例映琳,不會相互影響

o2[1].age = 23;
console.log(o1[1].age); // =>23 o1和o2內部包含的引用類型值机隙,復制的是其引用,會相互影響

可以通過Array.prototype.slice()jQuery中的$.extend({}, obj)完成對一個數(shù)組或者對象的淺拷貝萨西,我們也可以自己寫一個簡單淺拷貝函數(shù)來加深對淺拷貝的理解有鹿。

// 淺拷貝實現(xiàn),僅供參考
function shallowClone(source) {
    if (!source || typeof source !== 'object') {
        throw new Error('error arguments');
    }
    var targetObj = source.constructor === Array ? [] : {};
    for (var keys in source) {
        if (source.hasOwnProperty(keys)) {
            targetObj[keys] = source[keys];
        }
    }
    return targetObj;
}

深拷貝(deep copy)

深拷貝也就是拷貝出一個新的實例谎脯,新的實例和之前的實例互不影響葱跋,深拷貝的實現(xiàn)有幾種方法,首先我們可以借助jQuery源梭,lodash等第三方庫完成一個深拷貝實例娱俺。在jQuery中可以通過添加一個參數(shù)來實現(xiàn)遞歸extend,調用$.extend(true, {}, ...)就可以實現(xiàn)一個深拷貝废麻。

我們也可以自己實現(xiàn)一個深拷貝的函數(shù)荠卷,通常有兩種方式,一種就是用遞歸的方式來做烛愧,還有一種是利用JSON.stringifyJSON.parse來做油宜,這兩種方式各有優(yōu)劣掂碱,先來看看遞歸的方法怎么做。

jQuery中的extend方法基本的就是按照這個思路實現(xiàn)的慎冤,但是沒有辦法處理源對象內部循環(huán)引用的問題疼燥,同時對DateFunction等類型值也沒有實現(xiàn)真正的深度復制蚁堤,但是這些類型的值在重新定義的時候一般都是直接覆蓋醉者,所以也不會對源對象產生影響,從一定程度上來說也算是實現(xiàn)了一個深拷貝披诗。

// 遞歸實現(xiàn)一個深拷貝
function deepClone(source){
    if(!source || typeof source !== 'object'){
        throw new Error('error arguments', 'shallowClone');
    }
    var targetObj = source.constructor === Array ? [] : {};
    for(var keys in source){
        if(source.hasOwnProperty(keys)){
            if(source[keys] && typeof source[keys] === 'object'){
                targetObj[keys] = source[keys].constructor === Array ? [] : {};
                targetObj[keys] = deepClone(source[keys]);
            }else{
                targetObj[keys] = source[keys];
            }
        }
    }
    return targetObj;
}
// test example
var o1 = {
    arr: [1, 2, 3],
    obj: {
        key: 'value'
    },
    func: function(){
        return 1;
    }
};
var o3 = deepClone(o1);
console.log(o3 === o1); // => false
console.log(o3.obj === o1.obj); // => false
console.log(o2.func === o1.func); // => true

還有一種實現(xiàn)深拷貝的方式是利用 JSON 對象中的parsestringify撬即, JOSN對象中的stringify可以把一個
js 對象序列化為一個 JSON 字符串,parse可以把 JSON 字符串反序列化為一個 js 對象藤巢,通過這兩個方法搞莺,也可以實現(xiàn)對象的深復制。

我們從下面的例子就可以看到掂咒,源對象的方法在拷貝的過程中丟失了,這是因為在序列化JavaScript對象時迈喉,所有函數(shù)和原型成員會被有意忽略绍刮,這個實現(xiàn)可以滿足一些比較簡單的情況,能夠處理 JSON 格式所能表示的所有數(shù)據(jù)類型挨摸,同時如果在對象中存在循環(huán)應用的情況也無法正確處理孩革。

// 利用JSON序列化實現(xiàn)一個深拷貝
function deepClone(source){
    return JSON.parse(JSON.stringify(source));
}
var o1 = {
    arr: [1, 2, 3],
    obj: {
        key: 'value'
    },
    func: function(){
        return 1;
    }
};
var o2 = deepClone(o1);
console.log(o2); // => {arr: [1,2,3], obj: {key: 'value'}}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市得运,隨后出現(xiàn)的幾起案子膝蜈,更是在濱河造成了極大的恐慌,老刑警劉巖熔掺,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饱搏,死亡現(xiàn)場離奇詭異,居然都是意外死亡置逻,警方通過查閱死者的電腦和手機推沸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來券坞,“玉大人鬓催,你說我怎么就攤上這事『廾” “怎么了宇驾?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長猴伶。 經常有香客問我课舍,道長塌西,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任布卡,我火速辦了婚禮雨让,結果婚禮上,老公的妹妹穿的比我還像新娘忿等。我一直安慰自己栖忠,他們只是感情好,可當我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布贸街。 她就那樣靜靜地躺著庵寞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪薛匪。 梳的紋絲不亂的頭發(fā)上捐川,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天,我揣著相機與錄音逸尖,去河邊找鬼古沥。 笑死,一個胖子當著我的面吹牛娇跟,可吹牛的內容都是我干的岩齿。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼苞俘,長吁一口氣:“原來是場噩夢啊……” “哼盹沈!你這毒婦竟也來了?” 一聲冷哼從身側響起吃谣,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤乞封,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后岗憋,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肃晚,經...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年澜驮,在試婚紗的時候發(fā)現(xiàn)自己被綠了陷揪。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡杂穷,死狀恐怖悍缠,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情耐量,我是刑警寧澤飞蚓,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站廊蜒,受9級特大地震影響趴拧,放射性物質發(fā)生泄漏溅漾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一著榴、第九天 我趴在偏房一處隱蔽的房頂上張望添履。 院中可真熱鬧,春花似錦脑又、人聲如沸暮胧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽往衷。三九已至,卻和暖如春严卖,著一層夾襖步出監(jiān)牢的瞬間席舍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工哮笆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留来颤,地道東北人。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓稠肘,卻偏偏與公主長得像脚曾,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子启具,可洞房花燭夜當晚...
    茶點故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內容