JavaScript 深拷贝的实现
这里的深拷贝总体考虑的还是比较浅显的,主要是考虑引用类型中,我们需要把引用类型拷贝下来,这里主要考虑的引用类型,说白了其实还是很少的,主要就是自己定义的
object
和Array
。
在面试中,题目也是类似于拷贝数组一类的题。
当然,觉得自己的代码还是不够好看,希望菊苣们指摘。
另外,本来我也是喜欢直接写在原型上修改的,但是之前看到说原型上修改会出很多不可预知的错误(大家一起改),所以还是用传统的函数
整体的思考思路就是利用递归来进行饮用对象内的深拷贝,然后将其返回值赋给新的对象。
我们先来看看数组拷贝:
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)