Object.assign()的痛點

最近也一直會用javascript,然后中間使用的一些組件其弊,如Echarts 會有非常復雜的配置文件,而大部分配置可能都是一樣的膀斋,所以想著寫一份通用配置梭伐,然后,其他地方需要使用的時候仰担,用這份配置深拷貝一份配置糊识,然后在上面繼續(xù)改。就如下:
<script>
    const defaultOpt = {
        key1: xxx,
        key2: {
            dd: ee
        },
        .....
    };

    // deepCopy為某個實現(xiàn)深拷貝的方法
    const opt1 = deepCopy(defaultOpt);
    opt1.....
    const opt2 = deepCopy(defaultOpt);
    opt2.....
</script>

深拷貝和淺拷貝

這里也涉及到一個深拷貝和淺拷貝的概念摔蓝。javascript中存儲對象都是存地址的赂苗,所以淺拷貝是都指向同一塊內(nèi)存區(qū)塊,而深拷貝則是另外開辟了一塊區(qū)域贮尉。下面實例也可以看出這一點:
<script>
    // 淺拷貝
    const a = {
        t: 1,
        p: 'gg'
    };
    const b = a;
    b.t = 3;
    console.log(a); // {t: 3, p: 'gg'}
    console.log(b); // {t: 3, p: 'gg'}

    //深拷貝
    const c = {
        t: 1,
        p: 'gg'
    };
    const d = deepCopy(c);
    d.t = 3;
    console.log(c); // {t: 1, p: 'gg'}
    console.log(d); // {t: 3, p: 'gg'}
</script>
可以明顯看出拌滋,淺拷貝在改變其中一個值時,會導致其他也一起改變猜谚,而深拷貝不會败砂。

Object.assign()

我需要的是深拷貝的方法,然后發(fā)現(xiàn)原來es6 中有Object.assign() 這個方法魏铅,感覺可以拿來用了昌犹。
貼一下兩個官方例子:
 //1.
<script>
    // Cloning an object
    var obj = {
        a: 1
    };
    var copy = Object.assign({}, obj);
    console.log(copy); // { a: 1 }
</script>

 //2.
<script>
    // Merging objects
    var o1 = {
        a: 1
    };
    var o2 = {
        b: 2
    };
    var o3 = {
        c: 3
    };

    var obj = Object.assign(o1, o2, o3);
    console.log(obj); // { a: 1, b: 2, c: 3 }
    console.log(o1); // { a: 1, b: 2, c: 3 }, target object itself is changed.
</script>
是不是很完美,又可以clone又可以merge览芳。在我這種情況下斜姥,我覺得我的代碼量又可以減少了,比如:
<script>
    const defaultOpt = {
        title: 'hello',
        name: 'oo',
        type: 'line'
    };
    // 原來可能需要這樣
    const opt1 = deepCopy(a);
    opt1.title = 'opt1';
    opt1.type = 'bar';
    opt1.extra = 'extra'; // 額外增加配置
    // 現(xiàn)在只要這樣
    const opt2 = Object.assign({}, a, {
        title: 'opt2',
        type: 'bar',
        extra: 'extra'
    });
</script>

不過沧竟,很快疾渴,問題出現(xiàn)了,那就是

merge和我想象的不一樣

<script>
    const defaultOpt = {
        title: {
            text: 'hello world',
            subtext: 'It\'s my world.'
        }
    };

    const opt = Object.assign({}, defaultOpt, {
        title: {
            subtext: 'Yes, your world.'
        }
    });

    console.log(opt);

    // 預期結(jié)果
    {
        title: {
            text: 'hello world',
            subtext: 'Yes, your world.'
        }
    }
    // 實際結(jié)果
    {
        title: {
            subtext: 'Yes, your world.'
        }
    }
</script>
原本想的是它只會覆蓋subtext 屯仗,然而其實它直接覆蓋了整個title 搞坝,這個讓我比較郁悶,相當于它只merge根屬性魁袜,下面的就不做處理了桩撮。
代碼只能重構(gòu)成相對麻煩一點的:
<script>
    const defaultOpt = {
        title: {
            text: 'hello world',
            subtext: 'It\'s my world.'
        }
    };

    const opt = Object.assign({}, defaultOpt);
    opt.title.subtext = 'Yes, your world.';

    console.log(opt);
    // 結(jié)果正常
    {
        title: {
            text: 'hello world',
            subtext: 'Yes, your world.'
        }
    }
</script>
這樣用雖然麻煩一點,但是也還好峰弹,可以用了店量。不過。鞠呈。融师。很快,又出現(xiàn)問題了蚁吝,如下:
<script>
    const defaultOpt = {
        title: {
            text: 'hello world',
            subtext: 'It\'s my world.'
        }
    };

    const opt1 = Object.assign({}, defaultOpt);
    const opt2 = Object.assign({}, defaultOpt);
    opt2.title.subtext = 'Yes, your world.';

    console.log('opt1:');
    console.log(opt1);
    console.log('opt2:');
    console.log(opt2);

    // 結(jié)果
    opt1: {
        title: {
            text: 'hello world',
            subtext: 'Yes, your world.'
        }
    }
    opt2: {
        title: {
            text: 'hello world',
            subtext: 'Yes, your world.'
        }
    }
</script>
上面結(jié)果發(fā)現(xiàn)兩個配置變得一模一樣旱爆,而其實我們并沒有去更改opt1 的subtext 舀射,只是改了opt2 的。

這說明一點:在title 這一層只是簡單的淺拷貝 怀伦,而沒有繼續(xù)深入的深拷貝脆烟。
這里不經(jīng)讓我懷疑這個接口到底是怎么實現(xiàn)的,它到底是不是和我所想的一樣房待。
翻了一下官方文檔邢羔,發(fā)現(xiàn)它寫得一個Polyfill ,代碼我加了點注釋如下:

<script>
    if (!Object.assign) {
        // 定義assign方法
        Object.defineProperty(Object, 'assign', {
            enumerable: false,
            configurable: true,
            writable: true,
            value: function (target) { // assign方法的第一個參數(shù)
                'use strict';
                // 第一個參數(shù)為空桑孩,則拋錯
                if (target === undefined || target === null) {
                    throw new TypeError('Cannot convert first argument to object');
                }

                var to = Object(target);
                // 遍歷剩余所有參數(shù)
                for (var i = 1; i < arguments.length; i++) {
                    var nextSource = arguments[i];
                    // 參數(shù)為空拜鹤,則跳過,繼續(xù)下一個
                    if (nextSource === undefined || nextSource === null) {
                        continue;
                    }
                    nextSource = Object(nextSource);

                    // 獲取改參數(shù)的所有key值流椒,并遍歷
                    var keysArray = Object.keys(nextSource);
                    for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
                        var nextKey = keysArray[nextIndex];
                        var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
                        // 如果不為空?且可枚舉敏簿,則直接淺拷貝賦值
                        if (desc !== undefined && desc.enumerable) {
                            to[nextKey] = nextSource[nextKey];
                        }
                    }
                }
                return to;
            }
        });
    }
</script>
上面的代碼可以直接說明它只對頂層屬性做了賦值,完全沒有繼續(xù)做遞歸之類的把所有下一層的屬性做深拷貝镣隶。

總結(jié)

Object.assign()

只是一級屬性復制极谊,比淺拷貝多深拷貝了一層而已诡右。用的時候安岂,還是要注意這個問題的。

發(fā)現(xiàn)一個可以簡單實現(xiàn)深拷貝的方法帆吻,當然域那,有一定限制,如下:

const obj1 = JSON.parse(JSON.stringify(obj));

思路就是將一個對象轉(zhuǎn)成json字符串猜煮,然后又將字符串轉(zhuǎn)回對象次员。

轉(zhuǎn)載至:http://blog.csdn.net/waiterwaiter/article/details/50267787

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市王带,隨后出現(xiàn)的幾起案子淑蔚,更是在濱河造成了極大的恐慌,老刑警劉巖愕撰,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刹衫,死亡現(xiàn)場離奇詭異,居然都是意外死亡搞挣,警方通過查閱死者的電腦和手機带迟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來囱桨,“玉大人仓犬,你說我怎么就攤上這事∩岢Γ” “怎么了搀继?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵窘面,是天一觀的道長。 經(jīng)常有香客問我律歼,道長民镜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任险毁,我火速辦了婚禮制圈,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘畔况。我一直安慰自己鲸鹦,他們只是感情好,可當我...
    茶點故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布跷跪。 她就那樣靜靜地躺著馋嗜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪吵瞻。 梳的紋絲不亂的頭發(fā)上葛菇,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天,我揣著相機與錄音橡羞,去河邊找鬼眯停。 笑死,一個胖子當著我的面吹牛卿泽,可吹牛的內(nèi)容都是我干的莺债。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼签夭,長吁一口氣:“原來是場噩夢啊……” “哼齐邦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起第租,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤措拇,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后慎宾,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體丐吓,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年璧诵,在試婚紗的時候發(fā)現(xiàn)自己被綠了汰蜘。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡之宿,死狀恐怖族操,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤色难,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布泼舱,位于F島的核電站,受9級特大地震影響枷莉,放射性物質(zhì)發(fā)生泄漏娇昙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一笤妙、第九天 我趴在偏房一處隱蔽的房頂上張望冒掌。 院中可真熱鬧,春花似錦蹲盘、人聲如沸股毫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽铃诬。三九已至,卻和暖如春苍凛,著一層夾襖步出監(jiān)牢的瞬間趣席,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工醇蝴, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宣肚,地道東北人。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓哑蔫,卻偏偏與公主長得像钉寝,于是被迫代替她去往敵國和親弧呐。 傳聞我的和親對象是個殘疾皇子闸迷,可洞房花燭夜當晚...
    茶點故事閱讀 45,455評論 2 359

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

  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,160評論 30 470
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn)俘枫,斷路器腥沽,智...
    卡卡羅2017閱讀 134,696評論 18 139
  • 屬性的簡潔表示法 ES6允許直接寫入變量和函數(shù),作為對象的屬性和方法鸠蚪。這樣的書寫更加簡潔今阳。 上面代碼表明,ES6允...
    呼呼哥閱讀 2,925評論 0 2
  • 1.屬性的簡潔表示法 允許直接寫入變量和函數(shù) 上面代碼表明茅信,ES6 允許在對象之中盾舌,直接寫變量。這時蘸鲸,屬性名為變量...
    雨飛飛雨閱讀 1,138評論 0 3
  • 2017年4月20日妖谴,我們書記打電話告訴我,要我代表我們單位參加,片區(qū)的歌唱比賽膝舅。當時我一聽就蒙了嗡载。 平心而論,我...
    牛德華12345閱讀 489評論 0 1