CodeSky 代码之空

随手记录自己的学习过程

JavaScript 深拷贝的实现

2016-03-12 11:21分类: JavaScript评论: 0

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

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

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

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

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

我们先来看看数组拷贝:

1/**
2 * 实现数组的深拷贝
3 * 但是实际上,这种拷贝方式有许多种不足之处:比如丢失对象的原型链\函数的拷贝等等
4 * @param arr
5 * @returns {Array}
6 */
7var deepCopyOfArray = function(arr) {
8    var newArr = [], key, innerKey, tempObj = {};
9
10    for (key in arr) {
11        if (arr[key] instanceof Array) {
12            newArr.push(deepCopyOfArray(arr[key])); // 把深拷贝递归返回的数组添加到数组中
13        } else if (arr[key] instanceof Object) {
14            for (innerKey in arr[key]) {
15                if (typeof arr[key][innerKey] == 'object') {
16                    tempObj[innerKey] = deepCopyOfArray(arr[key][innerKey]);    // 递归复制
17                } else {
18                    tempObj[innerKey] = arr[key][innerKey];     // 将值传入对象
19                }
20            }
21
22            newArr.push(tempObj);   // 对象差存入数组
23            tempObj = {};   // 引用类型,我们需要新开一段空间来使得tempObj指向新对象
24        } else {
25            newArr.push(arr[key]);
26        }
27    }
28    return newArr;  // 返回数组
29};
30

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

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

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

1/**
2 * 解决了原型链问题的深拷贝
3 * @param obj
4 * @returns {*}
5 */
6var deepCopyOfObject = function(obj) {
7    var Constructor = obj.constructor,
8        newObj = null,
9        key;
10
11    if (typeof obj == 'object') {
12        newObj = new Constructor();
13        if (obj instanceof Array) {
14            for (key in obj) {
15                if (typeof obj[key] == 'object') {
16                    newObj.push(deepCopyOfObject(obj[key]));
17                } else {
18                    newObj.push(obj[key]);
19                }
20            }
21        } else {
22            for (key in obj) {
23                if (typeof obj[key] == 'object') {
24                    newObj[key] = deepCopyOfObject(obj[key]);
25                } else {
26                    newObj[key] = obj[key];
27                }
28            }
29        }
30    } else {
31        newObj = obj;
32    }
33
34    return newObj;
35};
36

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

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

评论 (0)