深克隆(deepclone)


1.簡單版:

<script type="text/javascript">
const newObj = JSON.parse(JSON.stringify(oldObj));
</script>

局限性:
他無法實現對函數 、RegExp等特殊對象的克隆
會拋棄對象的constructor,所有的構造函數會指向Object
對象有循環引用,會報錯

2.面試版:

        <script type="text/javascript">
            /**
             * deep clone
             * @param  {[type]} parent object 需要進行克隆的對象
             * @return {[type]}        深克隆后的對象
             */
            const clone = parent => {
                // 判斷類型
                const isType = (obj, type) => {
                    if (typeof obj !== "object") return false;
                    const typeString = Object.prototype.toString.call(obj);
                    let flag;
                    switch (type) {
                        case "Array":
                            flag = typeString === "[object Array]";
                            break;
                        case "Date":
                            flag = typeString === "[object Date]";
                            break;
                        case "RegExp":
                            flag = typeString === "[object RegExp]";
                            break;
                        default:
                            flag = false;
                    }
                    return flag;
                };

                // 處理正則
                const getRegExp = re => {
                    var flags = "";
                    if (re.global) flags += "g";
                    if (re.ignoreCase) flags += "i";
                    if (re.multiline) flags += "m";
                    return flags;
                };
                // 維護兩個儲存循環引用的數組
                const parents = [];
                const children = [];

                const _clone = parent => {
                    if (parent === null) return null;
                    if (typeof parent !== "object") return parent;

                    let child, proto;

                    if (isType(parent, "Array")) {
                        // 對數組做特殊處理
                        child = [];
                    } else if (isType(parent, "RegExp")) {
                        // 對正則對象做特殊處理
                        child = new RegExp(parent.source, getRegExp(parent));
                        if (parent.lastIndex) child.lastIndex = parent.lastIndex;
                    } else if (isType(parent, "Date")) {
                        // 對Date對象做特殊處理
                        child = new Date(parent.getTime());
                    } else {
                        // 處理對象原型
                        proto = Object.getPrototypeOf(parent);
                        // 利用Object.create切斷原型鏈
                        child = Object.create(proto);
                    }

                    // 處理循環引用
                    const index = parents.indexOf(parent);

                    if (index != -1) {
                        // 如果父數組存在本對象,說明之前已經被引用過,直接返回此對象
                        return children[index];
                    }
                    parents.push(parent);
                    children.push(child);

                    for (let i in parent) {
                        // 遞歸
                        child[i] = _clone(parent[i]);
                    }

                    return child;
                };
                return _clone(parent);
            };
        </script>

局限性:

一些特殊情況沒有處理: 例如Buffer對象、Promise、Set、Map
另外對於確保沒有循環引用的對象,我們可以省去對循環引用的特殊處理,因為這很消耗時間


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM