JavaScript 深拷贝的实现
这里的深拷贝总体考虑的还是比较浅显的,主要是考虑引用类型中,我们需要把引用类型拷贝下来,这里主要考虑的引用类型,说白了其实还是很少的,主要就是自己定义的object
和Array
。
在面试中,题目也是类似于拷贝数组一类的题。
当然,觉得自己的代码还是不够好看,希望菊苣们指摘。
另外,本来我也是喜欢直接写在原型上修改的,但是之前看到说原型上修改会出很多不可预知的错误(大家一起改),所以还是用传统的函数
整体的思考思路就是利用递归来进行饮用对象内的深拷贝,然后将其返回值赋给新的对象。
我们先来看看数组拷贝:
/**
* 实现数组的深拷贝
* 但是实际上,这种拷贝方式有许多种不足之处:比如丢失对象的原型链\函数的拷贝等等
* @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;
};
这里我们直接改为了对象的深拷贝流程。
如果要把递归改为迭代,来解决有可能的栈溢出的问题,最简单的是靠我们自己去构造一个栈来存放过程,这里就不再赘述了。
植入部分
如果您觉得文章不错,可以通过赞助支持我。
如果您不希望打赏,也可以通过关闭广告屏蔽插件的形式帮助网站运作。