1.区分深拷贝与浅拷贝
如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力。
2.浅拷贝
Object.prototype.num = 100;
const obj1 = {
name:'anjing',
age:21,
sex:'男',
car:'bike',
computer:'WEB',
message:{
address:'湖北',
like:'吃火锅',
girl:{
fourYear:'jiajia',
thressMonth:'no'
}
},
learn:['javaScript','css','HTML']
}
// 封装浅拷贝函数
function copy(oldObj,newObj) {
let target = newObj || {};
for(let key in oldObj) {
if(oldObj.hasOwnProperty(key)) {
target[key] = oldObj[key];
}
}
return target
}
此时obj2中也跟着变了,因为只能处理第一层的属性,如果第一层属性后面存在引用类型,则无法达到效果
3. 简化版-深拷贝
// 深拷贝
function deepCopy(oldObj, newObj) {
let target = newObj || {},
toStr = Object.prototype.toString,
arrType = '[object Array]';
// 开始遍历属性
for(let key in oldObj) {
if(oldObj.hasOwnProperty(key)) {
if(typeof(oldObj[key]) ==='object' && typeof oldObj[key] !== 'null') {
if(toStr.call(oldObj[key]) === arrType) {
target[key] = [];
}else {
target[key] = {};
}
deepCopy(oldObj[key],target[key])
}else {
target[key] = oldObj[key]
}
}
}
return target
}
深拷贝函数封装步骤
- 遍历刚开始将不属与私有属性的方法排除
- 判断属性是否为引用类型,不是对象则正常拷贝
- 如果属性为引用类型的对象,则 target[key] = {},如果为数组则target[key] = [];
- 通过递归来逐步排查更深层次的属性类型问题(递归的出口为当属性为字符串则停止运行)
- 将新对象返回
上面这种深拷贝只是简单实现,只对了原始obj,aray做了处理,
那么对于function,regexp,date也需要做处理
4.完善版深拷贝
const isComplexDataType = obj => (typeof obj === 'object' || typeof obj === 'function') && (obj !== null)
const deepClone = function (obj, hash = new WeakMap()) {
if (obj.constructor === Date)
return new Date(obj) // 日期对象直接返回一个新的日期对象
if (obj.constructor === RegExp)
return new RegExp(obj) //正则对象直接返回一个新的正则对象
//如果循环引用了就用 weakMap 来解决
if (hash.has(obj)) return hash.get(obj)
let allDesc = Object.getOwnPropertyDescriptors(obj)
//遍历传入参数所有键的特性
let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc)
//继承原型链
hash.set(obj, cloneObj)
for (let key of Reflect.ownKeys(obj)) {
cloneObj[key] = (isComplexDataType(obj[key]) && typeof obj[key] !== 'function') ? deepClone(obj[key], hash) : obj[key]
}
return cloneObj
}