这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战
背景
学习前端三个月了,准备刷刷面试题,总结总结,一天几道面试题,向大厂进军。
问题
深拷贝浅拷贝的区别?如何实现一个深拷贝?
解析:
数据的基本类型
我们大家都知道,js中存在两大数据类型:
- 基本类型
- 引用类型
基本类型数据保存在栈内存中 引用类型数据保存在堆内存中,引用数据类型的变量是一个指向堆内存的的实际引用地址,保存在栈中。
可以看图:
浅拷贝
浅拷贝,这里一定要理解拷贝的概念,拷贝是克隆一份新的出来。 浅拷贝与深拷贝的区别是拷贝的层级深度不一样。
如果属性是基本数据类型,拷贝就是基本数据类型的值,如果是引用类型,拷贝的就是内存地址。
在js中,存在浅拷贝的是:
- Object.assign
- Array.prototype.slice()
,Array.prototype.concat() - 使用ES6的扩展运算符实现复制
例子:
//Object.assign
var obj={name:"qxz",age:45,cc:{c:2}};
var newObj=Object.assign({},obj);
//扩展运算符
var c={a:{c:1,b:2},d:{f:3,e:3}};
var ff={...c};
自己实现一个浅拷贝:
function clone(obj) {
const newObj = {};
for(let prop in obj) {
if(obj.hasOwnProperty(prop)){
newObj[prop] = obj[prop];
}
}
return newObj;
}
深拷贝
深拷贝是开辟一个新的栈,两个对象的属性完全相同。修改其中一个对象的值,另外一个不受影响。
常见的深拷贝:
- _.cloneDeep(value)
- jQuery.extend()
- JSON.stringify() 对undefined,日期,symbol等会存在问题。
- 手写递归
例子:
//lodash
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]); //false
//JSON.stringify()
const newObj=JSON.parse(JSON.stringify(objects));
手动递归实现一个:
function deepClone(obj, hash = new WeakMap()) {
if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
// 可能是对象或者普通的值 如果是函数的话是不需要深拷贝
if (typeof obj !== "object") return obj;
// 是对象的话就要进行深拷贝
if (hash.get(obj)) return hash.get(obj);
let cloneObj = new obj.constructor();
// 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身
hash.set(obj, cloneObj);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 实现一个递归拷贝
cloneObj[key] = deepClone(obj[key], hash);
}
}
return cloneObj;
}
区别,一张图搞定
结语
一步一步慢慢来,踏踏实实把活干!