前端面試題——對象的深淺拷貝

在實際項目中翠储,我們往往需要對一個對象進(jìn)行拷貝绘雁,其目的可能是為了拷貝一個對象做其他處理,可能是為了擴(kuò)充一個對象使其擁有另一個對象的屬性援所,也可能是為了其他的目的

但是在 js 中庐舟,對象的拷貝分為深淺兩種,而不僅僅是將這個對象的屬性賦給另一個對象那么簡單住拭。同時對象的深淺拷貝也是很對前端面試中常見的一題挪略,所以下面就來詳細(xì)說說 js 中的 對象深淺拷貝,如果有誤滔岳,還請多多指正杠娱,共同進(jìn)步

值類型與引用類型

首先理解一下兩個概念:值類型引用類型

  • 值類型

簡單來說,值類型就是將一個變量賦值給另一個變量后谱煤,兩個變量完全獨立摊求,改變其中的一個并不會影響另一個

var a = 1;
var b = a; // b = 1
a = 2; // a = 2   b = 1

像上面的例子中,雖然后聲明的變量b賦予了a的值刘离,但是改變a的值室叉,b卻沒有改變

除了數(shù)值類型睹栖,與此類似的 js 中的值類型還有布爾值字符串茧痕、null野来、undefined

  • 引用類型

引用類型剛好與值類型相反,原始的變量被改變后凿渊,被賦值的變量也會被改變

引用類型會在內(nèi)存中開辟一塊區(qū)域保存它的值梁只,而被賦予了這個值的原始變量本質(zhì)上是將指向了這塊內(nèi)存,而被賦值的另一個變量獲得的也只是這個指向而已

所以一旦內(nèi)存上的值改變埃脏,所有只想這塊內(nèi)存的變量的值都會被改變

var c = [1,2,3];
var d = c; // d = [1,2,3]
c[0] = 0; // c = [0,2,3]   d = [0,2,3]

可能有的小伙伴會說搪锣,不對呀,下面這種情況 d 并沒有被改變

var c = [1,2,3];
var d = c; // d = [1,2,3]
c = [4,5,6]; // c = [4,5,6]   d = [1,2,3]

其實并沒有不對彩掐,上面例子中的 c[0] 改變的是原內(nèi)存地址中存儲的值构舟,因為c、d指向相同堵幽,所有都被改變狗超;而后一個例子中,為 c 重新賦值朴下,相當(dāng)于是在內(nèi)存中重新開辟了一塊區(qū)域存儲新值努咐,改變了 c 原來的指向,但 d 的指向卻沒有改變殴胧,所以我們看到的值也就沒變

js 中常見引用類型有 數(shù)組渗稍、對象函數(shù)

了解了值類型和引用類型团滥,下面我們開始進(jìn)入正題

對象的淺拷貝

對象的淺拷貝簡單竿屹,就是將一個變量賦給另一個變量

var obj1 = {
    name: 'test name',
    age: 18
}

var obj2 = obj1;

上面的例子中 obj2 經(jīng)過淺拷貝擁有了 obj1 的屬性

封裝淺拷貝方法

    var easyCopy = function ( extendObj ) {
        var newObj = extendObj.constructor === Array ? [] : {};
        if (typeof extendObj != 'object') return;
        for (var key in extendObj) {
            if (extendObj.hasOwnProperty(key)) {
                newObj[key] = extendObj[key];
            }
        }
        return newObj
    };

    var obj2 = {
        tall: 1.8,
        weight: 75
    }

    var obj1 = easyCopy( obj2 );

    console.log( obj1 );

淺拷貝存在的問題

我們知道引用類型的賦值其實是改變了變量的指向,那么如果在需要拷貝的對象中存在某個屬性的值是引用類型灸姊,如數(shù)組或子對象拱燃,那么淺拷貝后的原對象的屬性獲得的也只是這個指向

所以如果改變被拷貝對象的屬性值,那么原對象的相應(yīng)屬性也會跟著改變

    var obj2 = {
        names: ['test0', 'test1', 'test3']
    }

    obj1 = easyCopy( obj2 );

    console.log( obj1, obj2 );

    obj2.names[1] = 'test0';

    console.log( obj1, obj2 );

    // 打印結(jié)果為:obj1.name[1] 的值從原來的 'test1' 變成了 'test0'

日常項目中使用比較多的是淺拷貝力惯,但是如果某些情況下使用了淺拷貝碗誉,可能會產(chǎn)生一些極不容易發(fā)現(xiàn)的bug,所以這時候就需要用到深拷貝了

對象的深拷貝

深拷貝其實就是將對象中的數(shù)組夯膀、子對象進(jìn)行深度遞歸遍歷诗充,直到其不是引用類型位置再進(jìn)行復(fù)制,這樣即使改變了其中一個的值诱建,也不會影響到另一個

深拷貝的封裝

    var deepCopy = function( extendObj ){
        var str, newObj = extendObj.constructor === Array ? [] : {};
        if(typeof extendObj !== 'object'){
            return;
        } else if(window.JSON){
            str = JSON.stringify(extendObj);
            newObj = JSON.parse(str);
        } else {
            for(var key in extendObj){
              if (!extendObj.hasOwnProperty(key)) return;
                newObj[key] = typeof extendObj[key] === 'object' ?
                        cloneObj(extendObj[key]) : extendObj[key];
            }
        }
        return newObj;
    };

    var obj2 = {
        names: ['test0', 'test1', 'test3']
    }

    var obj1 = deepCopy( obj2 );

    console.log( obj1, obj2 );

    obj2.names[1] = 'test0';

    console.log( obj1, obj2 );

深拷貝的缺點

雖然深拷貝能夠避免淺拷貝出現(xiàn)的問題,但是卻會帶來性能上的問題碟绑,如果一個對象非常復(fù)雜或數(shù)據(jù)龐大俺猿,所消耗的性能將會是很可觀的

補(bǔ)充

** for … in**

for … in 可以用來遍歷任何一個對象茎匠,它會將該對象上的所有屬性全部遍歷出來,包括原型鏈上的屬性

由于可以遍歷出原型鏈上的屬性押袍,所以需要使用 hasOwnProperty 這個方法來判斷到底是不是這個對象自身的屬性

由于數(shù)組也是對象诵冒,for … in 也可以用來遍歷數(shù)組,但是 for … in 損耗性能較多谊惭,所以如果是遍歷數(shù)組的話最好使用 for 語句

遞歸調(diào)用

一個方法重復(fù)調(diào)用自身的情況叫做遞歸汽馋,但是需要注意的是,一定要有一個條件來結(jié)束遞歸圈盔,否則將會陷入無限的循環(huán)

var index = 1;
function fuckSelf() {
    if (index < 100) {
        index++;
        fuckSelf();
    }
} 
fuckSelf();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末豹芯,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子驱敲,更是在濱河造成了極大的恐慌铁蹈,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件众眨,死亡現(xiàn)場離奇詭異握牧,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)娩梨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進(jìn)店門沿腰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人狈定,你說我怎么就攤上這事颂龙。” “怎么了掸冤?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵厘托,是天一觀的道長。 經(jīng)常有香客問我稿湿,道長铅匹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任饺藤,我火速辦了婚禮包斑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘涕俗。我一直安慰自己罗丰,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布再姑。 她就那樣靜靜地躺著萌抵,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上绍填,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天霎桅,我揣著相機(jī)與錄音,去河邊找鬼讨永。 笑死滔驶,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的卿闹。 我是一名探鬼主播揭糕,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼锻霎!你這毒婦竟也來了著角?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤量窘,失蹤者是張志新(化名)和其女友劉穎雇寇,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蚌铜,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡锨侯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了冬殃。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片囚痴。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖审葬,靈堂內(nèi)的尸體忽然破棺而出深滚,到底是詐尸還是另有隱情,我是刑警寧澤涣觉,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布痴荐,位于F島的核電站,受9級特大地震影響官册,放射性物質(zhì)發(fā)生泄漏生兆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一膝宁、第九天 我趴在偏房一處隱蔽的房頂上張望鸦难。 院中可真熱鬧,春花似錦员淫、人聲如沸合蔽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拴事。三九已至沃斤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間挤聘,已是汗流浹背轰枝。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工捅彻, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留组去,地道東北人。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓步淹,卻偏偏與公主長得像从隆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子缭裆,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,515評論 2 359

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

  • 1.寫一個NSString類的實現(xiàn) +(id)initWithCString:(c*****t char *)nu...
    韓七夏閱讀 3,772評論 2 37
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法键闺,類相關(guān)的語法,內(nèi)部類的語法澈驼,繼承相關(guān)的語法辛燥,異常的語法,線程的語...
    子非魚_t_閱讀 31,663評論 18 399
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,161評論 30 470
  • 累 最近這段時期只能用這個字來詮釋 工作壓力巨大缝其,奈何豬一樣的隊友同事讓我無奈挎塌。 生活壓力巨大,無他内边,囊中羞澀榴都,與...
    HowieGao閱讀 107評論 0 1
  • “傻”!這個字從不同人嘴里蹦出來漠其,感覺是不一樣的嘴高。戀人口中可能是,小傻子和屎,小笨蛋這是一種愛稱拴驮,濃情蜜意的感覺;特別...
    亻亻卩卩玬刐閱讀 540評論 0 0