Angular 的copy方法源碼解析

轉(zhuǎn)

// 好像是 Angular 的源碼,下面用了 ngMinErr萝毛,是 Angular 的慣用命名法

function copy(source, destination, stackSource, stackDest) {
    if (isWindow(source) || isScope(source)) {
        throw ngMinErr('cpws',
            "Can't copy! Making copies of Window or Scope instances is not supported.");
    }

    // destination 判 false 的情況,比如 0, "", NaN, undefined, null 等
    // 具體參考 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness
    if (!destination) {  // 分支1
        // 默認賦值滑黔,相當于在最后加 else  [參考(1)>
        destination = source;
        if (source) {
            if (isArray(source)) {
                // 如果 source 是數(shù)據(jù)笆包,把 destination 初始化為數(shù)組,再遞歸調(diào)用 copy(會進入分支②)
                destination = copy(source, [], stackSource, stackDest);
            } else if (isDate(source)) {
                // 如果是日期略荡,直接 source 的值構(gòu)造一個新的日期對象
                destination = new Date(source.getTime());
            } else if (isRegExp(source)) {
                // 復制正則表達式
                destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
                destination.lastIndex = source.lastIndex;
            } else if (isObject(source)) {
                // 如果是其它對象庵佣,把 destination 初始化為空對象,再遞歸調(diào)用 copy(會進入分支②)
                destination = copy(source, {}, stackSource, stackDest);
            }
            // else { destination = source } <參考(1)]
        }
    } else {    // 分支 2
        if (source === destination) throw ngMinErr('cpi',
            "Can't copy! Source and destination are identical.");

        stackSource = stackSource || [];
        stackDest = stackDest || [];

        if (isObject(source)) {
            // 看樣子這里是在處理遞歸引用汛兜,如果在 stackSource 里找到了 source
            // 說明之前已經(jīng)產(chǎn)生了這個對象的副本巴粪,直接從 stackDest 返回那個副本就好
            var index = indexOf(stackSource, source);
            if (index !== -1) return stackDest[index];

            // 壓棧,用于以后的遞歸引用檢查
            stackSource.push(source);
            stackDest.push(destination);
        }

        var result;
        if (isArray(source)) {
            destination.length = 0;
            for (var i = 0; i < source.length; i++) {
                // 這里遞歸調(diào)用 copy 主要是為了深度拷貝粥谬,
                // 因為 source[i] 也有可能是一個多么復雜的對象肛根,或者數(shù)組,或者其它……
                result = copy(source[i], null, stackSource, stackDest);
                if (isObject(source[i])) {
                    // 拷貝完了記得壓入引用棧帝嗡,供以后檢查
                    stackSource.push(source[i]);
                    stackDest.push(result);
                }
                destination.push(result);
            }
        } else {
            var h = destination.$$hashKey;

            // 先重置 destination
            if (isArray(destination)) {
                // 如果是數(shù)組,清空
                destination.length = 0;
            } else {
                // 如果不是數(shù)組璃氢,刪除所有屬性
                forEach(destination, function(value, key) {
                    delete destination[key];
                });
            }

            // 循環(huán)獲取 source 的每一個屬性哟玷,賦值給 destination
            // 同樣需要深拷貝,同樣需要緩存到引用棧
            for (var key in source) {
                result = copy(source[key], null, stackSource, stackDest);
                if (isObject(source[key])) {
                    stackSource.push(source[key]);
                    stackDest.push(result);
                }
                destination[key] = result;
            }

            // setHashKey 干啥的……我猜是 Angular 內(nèi)機制要用的
            setHashKey(destination, h);
        }

    }

    // 結(jié)果返回出去一也,注意到上面多處遞歸調(diào)用 copy 都是要取返回值的
    return destination;
}

其實這段代碼的邏輯還是很清楚巢寡,只在 stackSource 和 stackDest 加上遞歸,會稍稍讓人暈乎椰苟∫衷拢拷貝,尤其是深拷貝舆蝴,需要特別注意遞歸引用(就是常說的循環(huán)引用)的問題谦絮,所以這兩個 stack 就是緩存引用,用來處理遞歸引用的洁仗。遞歸层皱,這個是編程的基本技能之一,如果不懂赠潦,就只好先去看看教科書了isWindow 可以猜出來是判斷是否 window 對象的叫胖,isScope 不是很明白,看它的源碼應該能懂她奥,不過這里不 care瓮增,反正就是為了判斷不能拷貝的對象怎棱。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市绷跑,隨后出現(xiàn)的幾起案子拳恋,更是在濱河造成了極大的恐慌,老刑警劉巖你踩,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诅岩,死亡現(xiàn)場離奇詭異,居然都是意外死亡带膜,警方通過查閱死者的電腦和手機吩谦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來膝藕,“玉大人式廷,你說我怎么就攤上這事肴茄∪笥#” “怎么了舱痘?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵币喧,是天一觀的道長析校。 經(jīng)常有香客問我幸乒,道長垃它,這世上最難降的妖魔是什么迁霎? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任辛馆,我火速辦了婚禮俺陋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘昙篙。我一直安慰自己腊状,他們只是感情好,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布苔可。 她就那樣靜靜地躺著缴挖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪焚辅。 梳的紋絲不亂的頭發(fā)上映屋,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天,我揣著相機與錄音同蜻,去河邊找鬼秧荆。 笑死,一個胖子當著我的面吹牛埃仪,可吹牛的內(nèi)容都是我干的乙濒。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼颁股!你這毒婦竟也來了么库?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤甘有,失蹤者是張志新(化名)和其女友劉穎诉儒,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體亏掀,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡忱反,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了滤愕。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片温算。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖间影,靈堂內(nèi)的尸體忽然破棺而出注竿,到底是詐尸還是另有隱情,我是刑警寧澤魂贬,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布巩割,位于F島的核電站,受9級特大地震影響付燥,放射性物質(zhì)發(fā)生泄漏宣谈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一键科、第九天 我趴在偏房一處隱蔽的房頂上張望闻丑。 院中可真熱鬧,春花似錦萝嘁、人聲如沸梆掸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至怪得,卻和暖如春咱枉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背徒恋。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工蚕断, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人入挣。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓亿乳,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子葛假,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

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

  • 1. Java基礎部分 基礎部分的順序:基本語法障陶,類相關的語法,內(nèi)部類的語法聊训,繼承相關的語法抱究,異常的語法,線程的語...
    子非魚_t_閱讀 31,644評論 18 399
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,185評論 25 707
  • 這篇文章是我之前翻閱了不少的書籍以及從網(wǎng)絡上收集的一些資料的整理带斑,因此不免有一些不準確的地方鼓寺,同時不同JDK版本的...
    高廣超閱讀 15,614評論 3 83
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy閱讀 9,519評論 1 51
  • 分手一個禮拜,沒有人每天打電話噓寒問暖勋磕,嗯妈候,有點不習慣。 分手半個月朋凉,沒有人每天早晚跟我說早安晚安州丹,嗯,開始懷念杂彭。...
    三月殤閱讀 145評論 0 0