从一个变量给另一个变量赋值基本类型时,是从该变量上创建一个新值,然后复制到新变量分配的位置上。所以,新旧变量发生变化,是不会相互影响的。
但,当一个变量给另一个变量赋值引用类型时,也会复制一个值(变量标识符和指向堆内存的指针)到栈区内,他们指向的其实是同一个堆内存中的地址,所以他们当其一发生变化时,另一个变量将会受到影响。
以上知识点可以查看 数据类型和类型判断
所以,数据的深拷贝,是针对引用型变量来说的,常见的有 数组 和 对象。
function copy(obj, stack) {
// 如果是基本类型的值/function/null 直接返回
if (typeof obj !== 'object' || obj === null || obj === 'function') {
return obj;
}
return deepCopy(obj, stack);
}
function deepCopy(obj, stack) {
var className = Object.prototype.toString.call(obj);
var result;
stack = stack || [];
var length = stack.length;
while (length--) {
// 解决循环引用拷贝出错,及特殊类型 regExp,Date 拷贝返回数据不对的问题
if (stack[length] === obj || ['[object RegExp]', '[object Date]'].indexOf(className) > -1) return obj;
}
// 入栈
stack.push(obj);
if (className=== "[object Array]") {
// 递归
result = obj.map(item => copy(item, stack));
} else {
result = {};
for (let item in obj) {
// 递归
result[item] = copy(obj[item], stack);
}
}
// 出栈
stack.pop();
return result;
}
当然,使用 JSON.parse(JSON.stringify(obj)) 也能解决大部分的问题,可以满足日常工作所需。
举几个 JSON.parse(JSON.stringify(obj)) 也无能为力的情况:
- 循环引用
- 正则对象
- Date的值变成了字符串
上面的递归函数也有很多没考虑到的情况,可以参考这篇文章 JavaScript深拷贝的一些坑 。
所以,造轮子费心费力,更多是为了学习。
参考: