JavaScript 对象的深复制

时间:2021-11-17 04:19:43

对象的深复制

  • 源对象的属性更改,不会引起复制后的对象个属性的更改
  • 源对象的任何属性与子属性与新对象的之间没有任何引用关系

Coding:

/*
  对象的深复制:
    1 初始化目标对象
        如果没有指定目标对象,则利用源对象的构造函数创建目标对象,判断源对象类型,正则对象和日期对象分开复制
            如果源对象是正则对象,抽取源对象属性source和flag放入构造参数中新建目标对象
            如果源对象是日期对象,抽取源对象放入构造参数中新建目标对象
    2 复制属性并返回结果
        以数组形式获取源对象的所有属性名
        遍历数组,获取每个属性名对象的属性描述对象
        如果属性值是对象:
            将源对象的属性描述对象设置到对应的目标对象属性里面去
            考虑到属性对象可能存在嵌套,将当前属性value设置为属性描述对象value的递归遍历结果
        如果属性值是函数:
            正则提取函数参数和函数体内容,使用构造函数创建的形式将参数传进去
            设置value为fn,其他三个描述属性参照描述属性对象
        如果属性值不是函数也不是对象,只是普通属性,那么直接将源属性对应的属性名和属性描述设置给目标属性
*/
        function cloneObject(sourceObj, targetObj) {
            if (!sourceObj) return {};
            if (!targetObj) {
                targetObj = new sourceObj.constructor();
                switch (targetObj.constructor) {
                    case RegExp:
                        targetObj = new RegExp(sourceObj.source, sourceObj.flag);
                        break;
                    case Date:
                        targetObj = new Date(sourceObj);
                        break;
                }
            }
            var names = Object.getOwnPropertyNames(sourceObj);
            for (var i = 0; i < names.length; i++) {
                var desc = Object.getOwnPropertyDescriptor(sourceObj, names[i]);
                if (typeof desc.value === "object") {
                    var o = cloneObject(desc.value);
                    Object.defineProperty(targetObj, names[i], {
                        configurable: desc.configurable,
                        enumerable: desc.enumerable,
                        writable: desc.writable,
                        value: o
                    });
                } else if (typeof desc.value === "function") {
                    var fnStr = desc.value.toString().replace(/\n/g, "");
                    //非贪婪匹配,满足情况只取一次
                    var arg = fnStr.match(/\((.*?)\)/)[1];
                    //贪婪匹配,取{}的任意字符
                    var content = fnStr.match(/{(.*)}/)[1];
                    var fn = new Function(arg, content);
                    //设置函数名
                    Object.defineProperty(fn, "name", {
                        writable: true,
                        value: desc.value.name
                    });
                    Object.defineProperty(targetObj, names[i], {
                        configurable: desc.configurable,
                        enumerable: desc.enumerable,
                        writable: desc.writable,
                        value: fn
                    });
                } else {
                    Object.defineProperty(targetObj, names[i], desc);
                }
            }
            return targetObj;
        }

运行结果:

JavaScript 对象的深复制