深克隆(deepclone)

本文详细介绍了JavaScript中深拷贝的两种实现方法:一种是简单的JSON.parse和JSON.stringify组合,另一种是更为复杂的递归函数实现,后者能处理更多类型的对象,包括数组、日期、正则表达式等。文章还讨论了每种方法的局限性,如无法处理函数、特殊对象和循环引用的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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
另外对于确保没有循环引用的对象,我们可以省去对循环引用的特殊处理,因为这很消耗时间

转载于:https://www.cnblogs.com/wangxi01/p/11590189.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值