JavaScript 深拷贝的实现

这里的深拷贝总体考虑的还是比较浅显的,主要是考虑引用类型中,我们需要把引用类型拷贝下来,这里主要考虑的引用类型,说白了其实还是很少的,主要就是自己定义的objectArray

在面试中,题目也是类似于拷贝数组一类的题。

当然,觉得自己的代码还是不够好看,希望菊苣们指摘。

另外,本来我也是喜欢直接写在原型上修改的,但是之前看到说原型上修改会出很多不可预知的错误(大家一起改),所以还是用传统的函数

整体的思考思路就是利用递归来进行饮用对象内的深拷贝,然后将其返回值赋给新的对象。

我们先来看看数组拷贝:

/**
 * 实现数组的深拷贝
 * 但是实际上,这种拷贝方式有许多种不足之处:比如丢失对象的原型链\函数的拷贝等等
 * @param arr
 * @returns {Array}
 */
var deepCopyOfArray = function(arr) {
    var newArr = [], key, innerKey, tempObj = {};

    for (key in arr) {
        if (arr[key] instanceof Array) {
            newArr.push(deepCopyOfArray(arr[key])); // 把深拷贝递归返回的数组添加到数组中
        } else if (arr[key] instanceof Object) {
            for (innerKey in arr[key]) {
                if (typeof arr[key][innerKey] == 'object') {
                    tempObj[innerKey] = deepCopyOfArray(arr[key][innerKey]);    // 递归复制
                } else {
                    tempObj[innerKey] = arr[key][innerKey];     // 将值传入对象
                }
            }

            newArr.push(tempObj);   // 对象差存入数组
            tempObj = {};   // 引用类型,我们需要新开一段空间来使得tempObj指向新对象
        } else {
            newArr.push(arr[key]);
        }
    }
    return newArr;  // 返回数组
};

但是如同注释中所言,这个方法有几个缺陷,首先的一大问题就是对象丢失了其原本的原型链,我们可以使用对拷贝后的对象进行instanceof,结果会发现并不属于原本的对象原型。

要解决这个问题,我们只要稍作修改即可。

我们使用new来进行对象的创建而不是字面量即可:

/**
 * 解决了原型链问题的深拷贝
 * @param obj
 * @returns {*}
 */
var deepCopyOfObject = function(obj) {
    var Constructor = obj.constructor,
        newObj = null,
        key;

    if (typeof obj == 'object') {
        newObj = new Constructor();
        if (obj instanceof Array) {
            for (key in obj) {
                if (typeof obj[key] == 'object') {
                    newObj.push(deepCopyOfObject(obj[key]));
                } else {
                    newObj.push(obj[key]);
                }
            }
        } else {
            for (key in obj) {
                if (typeof obj[key] == 'object') {
                    newObj[key] = deepCopyOfObject(obj[key]);
                } else {
                    newObj[key] = obj[key];
                }
            }
        }
    } else {
        newObj = obj;
    }

    return newObj;
};

这里我们直接改为了对象的深拷贝流程。

如果要把递归改为迭代,来解决有可能的栈溢出的问题,最简单的是靠我们自己去构造一个栈来存放过程,这里就不再赘述了。

植入部分

如果您觉得文章不错,可以通过赞助支持我。

如果您不希望打赏,也可以通过关闭广告屏蔽插件的形式帮助网站运作。

标签: 知识, 代码段

添加新评论