深拷貝與淺拷貝的實現(xiàn)(一)

最近的學(xué)習(xí)中驰凛,仔細(xì)研究了下深拷貝和淺拷貝胸懈,下面就來簡單的總結(jié)下。

數(shù)據(jù)類型

首先我們了解下兩種數(shù)據(jù)類型
1恰响、基本類型:像Number趣钱、String、Boolean等這種為基本類型
2胚宦、復(fù)雜類型:Object和Array

淺拷貝與深拷貝的概念

接著我們分別來了解下淺拷貝和深拷貝首有,深拷貝和淺拷貝是只針對Object和Array這樣的復(fù)雜類型的。
淺拷貝

var a = {
    myname: 'yana'
};
var b = a;
b.myname = '小雅';
console.log(b.myname);    // 小雅
console.log(a.myname);    // 小雅
var a = ['myname', 'yana'];
var b = a;
b[1] = '小雅';
console.log(a);    // ["myname", "小雅"]
console.log(b);    // ["myname", "小雅"]

可以看出枢劝,對于對象或數(shù)組類型井联,當(dāng)我們將a賦值給b,然后更改b中的屬性您旁,a也會隨著變化烙常。也就是說a和b指向了同一塊內(nèi)存,所以修改其中任意的值鹤盒,另一個值都會隨之變化蚕脏,這就是淺拷貝。

深拷貝
剛剛我們了解了什么是淺拷貝侦锯,那么相應(yīng)的驼鞭,如果給b放到新的內(nèi)存中,將a的各個屬性都復(fù)制到新內(nèi)存里尺碰,就是深拷貝挣棕。
也就是說,當(dāng)b中的屬性有變化的時候亲桥,a內(nèi)的屬性不會發(fā)生變化洛心。

淺拷貝

那么除了上面簡單的賦值引用,還有哪些方法使用了淺拷貝呢两曼?
Object.assign()
在MDN上介紹Object.assign():”O(jiān)bject.assign() 方法用于將所有可枚舉的屬性的值從一個或多個源對象復(fù)制到目標(biāo)對象皂甘。它將返回目標(biāo)對象玻驻〉看眨”
復(fù)制一個對象

var target = {a: 1, b: 1};
var copy1 = {a: 2, b: 2, c: {ca: 21, cb: 22, cc: 23}};
var copy2 = {c: {ca: 31, cb: 32, cd: 34}};
var result = Object.assign(target, copy1, copy2);
console.log(target);    // {a: 2, b: 2, c: {ca: 31, cb: 32, cc: 33}}
console.log(target === result);    // true

可以看到偿枕,Object.assign()拷貝的只是屬性值,假如源對象的屬性值是一個指向?qū)ο蟮囊没П瑁仓豢截惸莻€引用值渐夸。所以O(shè)bject.assign()只能用于淺拷貝或是合并對象。這是Object.assign()值得注意的地方渔欢。

深拷貝

那么下面我們就來說說復(fù)雜的深拷貝墓塌。
jQuery.extend()
說到深拷貝,第一想到的就是jQuery.extend()方法奥额,下面我們簡單看下jQuery.extend()的使用苫幢。
jQuery.extend( [deep ], target, object1 [, objectN ] ),其中deep為Boolean類型垫挨,如果是true韩肝,則進(jìn)行深拷貝。
我們還是用上面的數(shù)據(jù)來看下extend()方法九榔。

var target = {a: 1, b: 1};
var copy1 = {a: 2, b: 2, c: {ca: 21, cb: 22, cc: 23}};
var copy2 = {c: {ca: 31, cb: 32, cd: 34}};
var result = $.extend(true, target, copy1, copy2);   // 進(jìn)行深拷貝
console.log(target);    // {a: 2, b: 2, c: {ca: 31, cb: 32, cc: 23, cd: 34}}
 
var target = {a: 1, b: 1};
var copy1 = {a: 2, b: 2, c: {ca: 21, cb: 22, cc: 23}};
var copy2 = {c: {ca: 31, cb: 32, cd: 34}};
var result = $.extend(target, copy1, copy2);   // 不進(jìn)行深拷貝
console.log(target);    // {a: 1, b: 1, c: {ca: 31, cb: 32, cd:34}}
 

通過上面的對比可以看出哀峻,當(dāng)使用extend()進(jìn)行深拷貝的時候,對象的所有屬性都添加到target中了哲泊。
我們知道了extend()可以進(jìn)行深拷貝剩蟀,那么extend()是如何實現(xiàn)深拷貝的呢?
先來看下jQuery.extend()源碼

jQuery.extend = jQuery.fn.extend = function() {
    var options, name, src, copy, copyIsArray, clone,
        target = arguments[ 0 ] || {},
        i = 1,
        length = arguments.length,
        deep = false;
 
    // Handle a deep copy situation
    if ( typeof target === "boolean" ) {
        deep = target;
 
        // Skip the boolean and the target
        target = arguments[ i ] || {};
        i++;
    }
 
    // Handle case when target is a string or something (possible in deep copy)
    if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
        target = {};
    }
 
    // Extend jQuery itself if only one argument is passed
    if ( i === length ) {
        target = this;
        i--;
    }
 
    for ( ; i < length; i++ ) {
 
        // Only deal with non-null/undefined values
        if ( ( options = arguments[ i ] ) != null ) {
 
            // Extend the base object
            for ( name in options ) {
                src = target[ name ];
                copy = options[ name ];
 
                // Prevent never-ending loop
                if ( target === copy ) {
                    continue;
                }
 
                // Recurse if we're merging plain objects or arrays
                if ( deep && copy && ( jQuery.isPlainObject( copy ) || ( copyIsArray = Array.isArray( copy ) ) ) ) {
 
                    if ( copyIsArray ) {
                        copyIsArray = false;
                        clone = src && Array.isArray( src ) ? src : [];
 
                    } else {
                        clone = src && jQuery.isPlainObject( src ) ? src : {};
                    }
 
                    // Never move original objects, clone them
                    target[ name ] = jQuery.extend( deep, clone, copy );
 
                // Don't bring in undefined values
                } else if ( copy !== undefined ) {
                    target[ name ] = copy;
                }
            }
        }
    }
    // Return the modified object
    return target;
};

主要看下關(guān)于深拷貝的部分切威,取第一個參數(shù)育特,如果是boolean類型的,就賦值給deep先朦,下面如果deep為true(也就是進(jìn)行深拷貝)且预,就遞歸調(diào)用extend(),這樣就將對象的所有屬性都添加到了target中實現(xiàn)了深拷貝烙无。

JSON.parse()和JSON.stringify()

上面的jQuery源碼是否讓你眼花繚亂锋谐?有沒有什么辦法無腦實現(xiàn)深拷貝呢?JSON.parse()和JSON.stringify()給了我們一個基本的解決辦法截酷。

var target = {a: 1, b: 1, c: {ca: 11, cb: 12, cc: 13}};
var targetCopy = JSON.parse(JSON.stringify(target));
targetCopy.a = 2;
targetCopy.c.ca = 21;
console.log(target);   // {a: 1, b: 1, c: {ca: 11, cb: 12, cc: 13}}
console.log(targetCopy);    // {a: 2, b: 1, c: {ca: 21, cb: 12, cc: 13}}
console.log(target === targetCopy);  // false

可以看到改變targetCopy并沒有改變原始的target涮拗,繼承的屬性也沒有丟失,因此實現(xiàn)了基本的深拷貝迂苛。
但是用JSON.parse()和JSON.stringify()會有一個問題三热。
JSON.parse()和JSON.stringify()能正確處理的對象只有Number、String三幻、Array等能夠被json表示的數(shù)據(jù)結(jié)構(gòu)就漾,因此函數(shù)這種不能被json表示的類型將不能被正確處理。

var target = {
    a: 1,
    b: 2,
    hello: function() { 
            console.log("Hello, world!");
    }
};
var copy = JSON.parse(JSON.stringify(target));
console.log(copy);   // {a: 1, b: 2}

上面的例子可以看出念搬,hello這個屬性由于是函數(shù)類型抑堡,使用JSON.parse()和JSON.stringify()后丟失了摆出。
因此JSON.parse()和JSON.stringify()還是需要謹(jǐn)慎使用。

轉(zhuǎn)載自AlloyTeam:http://www.alloyteam.com/2017/08/12978/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末首妖,一起剝皮案震驚了整個濱河市偎漫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌有缆,老刑警劉巖象踊,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異棚壁,居然都是意外死亡杯矩,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進(jìn)店門袖外,熙熙樓的掌柜王于貴愁眉苦臉地迎上來菊碟,“玉大人,你說我怎么就攤上這事在刺∧婧Γ” “怎么了?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵蚣驼,是天一觀的道長魄幕。 經(jīng)常有香客問我,道長颖杏,這世上最難降的妖魔是什么纯陨? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮留储,結(jié)果婚禮上翼抠,老公的妹妹穿的比我還像新娘。我一直安慰自己获讳,他們只是感情好阴颖,可當(dāng)我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著丐膝,像睡著了一般量愧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上帅矗,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天偎肃,我揣著相機(jī)與錄音,去河邊找鬼浑此。 笑死累颂,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的凛俱。 我是一名探鬼主播紊馏,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼料饥,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了瘦棋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤暖哨,失蹤者是張志新(化名)和其女友劉穎赌朋,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體篇裁,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡沛慢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了达布。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片团甲。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖黍聂,靈堂內(nèi)的尸體忽然破棺而出躺苦,到底是詐尸還是另有隱情,我是刑警寧澤产还,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布匹厘,位于F島的核電站,受9級特大地震影響脐区,放射性物質(zhì)發(fā)生泄漏愈诚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一牛隅、第九天 我趴在偏房一處隱蔽的房頂上張望炕柔。 院中可真熱鬧,春花似錦媒佣、人聲如沸匕累。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哩罪。三九已至,卻和暖如春巡验,著一層夾襖步出監(jiān)牢的瞬間际插,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工显设, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留框弛,地道東北人。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓捕捂,卻偏偏與公主長得像瑟枫,于是被迫代替她去往敵國和親斗搞。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,440評論 2 348

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