在JavaScript中进行数据拷贝的时候, 根据数据的类型分为深拷贝和浅拷贝, 如果拷贝的数据为基本类型, 浅拷贝即可, 如果拷贝的类型是引用类型, 想真正意义的进行拷贝, 就需要进行深拷贝
这里就不详细讲述深拷贝和浅拷贝的区别了, 它们的区别是因为基本类型和引用类型的数据类型造成的.
基本类型可以通过a = b
, 这种方式进行拷贝, 但是如果是引用类型的话, a = b
, 只是把b
的内存地址拷贝给了a
, 这样就会造成, 拷贝完之后我改变b
变量的某些值时, a
也会被改变, 因为它们的内存地址是一样的, 这时候就需要进行深拷贝。
深拷贝的方法也有很多很多, 像比较简单的通过JSON.stringify + JSON.parse
就可以实现深拷贝, 但是如果我们在面试的时候被问到, 面试官是打算让你用下面这种方式实现, 可以考察你的基本功。
var obj = {
name: "CreatorRay",
age: 21,
info: {
hobby: [
"play",
"game",
{
a: 1,
},
],
career: {
teacher: 4,
engineer: 9,
},
play: () => { console.log(1111); }
},
};
这个obj
就是我们要进行深拷贝的数据, 这个数据中各种类型都用到了, 可以验证是否实现了深拷贝
function deepClone (origin, target) {
let tar = target || {};
let toStr = Object.prototype.toString;
let arrType = '[object Array]';
for (let k in origin) {
// 是自己的属性再进行拷贝
if (origin.hasOwnProperty(k)) {
if (typeof origin[k] === 'object' && origin[k] !== null) {
tar[k] = toStr.call(origin[k]) === arrType ? [] : {};
deepClone(origin[k], tar[k]);
}else {
tar[k] = origin[k];
}
}
}
return tar;
}
先说一下思路:
- 进行拷贝之前要先保证, 要拷贝的值是存在的, 如果不存在就赋一个空对象
- 对被拷贝的数据进行
for in
循环, 进行拷贝之前要先保证现在拷贝的属性是自己的 - 对属性进行拷贝的时候要区分现在的属性是什么类型, 基本类型的话就直接拷贝, 引用类型的话就继续对当前属性进行递归
- 在判断当前属性是否是对象或者数组的时候, 方法也很多, 我这里用到的是
Object.property.toString
方法, 这个方法要返回一个[object xxx]
的字符串, 如果是数组的话就是[object Array]
, 如果是对象的话就是[object Object]
, 在用的时候继续改变一下this
指向。
主体思路就是这些, 当前要实现一个完美的深拷贝还要考虑很多很多的细节。
下面我们来验证一下写的是否正确
const newObj = deepClone(obj, {});
newObj.info.hobby[2].a = 999;
console.log(obj, newObj);
可以看到我们通过deepClone
拷贝完之后, 改变其中一个对象的属性中某个值后, 另一个对象相应的值并没有受到影响, 说明我们这个深拷贝函数写的没有问题。