浅拷贝
创建一个对象 这个对象有着和原始对象属性值一样的拷贝结果
如果属性是基本类型 则拷贝的是基本类型的值
如果属性是引用类型(object Array等)拷贝的是内存地址 修改此对象会影响另一个对象
function simplyCopy(target) {
let newtarget = {}
for(const key in target){
/* 直接拷贝属性值 */
newtarget[key] = target[key]
}
return newtarget
}
js 的 API
数组
-
splice concat都是浅拷贝特殊点:如果只有一层元素是深拷贝 后面层数是浅拷贝 拷贝引用地址
-
Object.assign(obj,sources)obj: 目标对象 sources:源对象特殊点:如果只有一级元素是深拷贝 后面级数是浅拷贝 拷贝引用地址
-
[...arr]
特殊点:适用于数组 如果只有一级元素是深拷贝 后面级数是浅拷贝 拷贝引用地址
深拷贝
和浅拷贝基本相似 只不过拷贝出来的对象之间不会相互干扰
JSON.parse(JSON.stringify());/* 简单版 */
/* 函数不会被拷贝到 */
代码思路:
- 对拷贝对象的属性值区分对待
- 如果是基本数据类型 直接返回
- 如果是引用类型 区分是数组还是对象
- 边界处理 如果对象间接或直接引用自身引起对
deepCopy()的循环 - 其他引用类型 null Function set Map对其属性值的再一次拷贝
- Bool Number String Date Error RegExp构造函数和原始数据
/*
使用WeakMap来处理循环克隆问题
同时存在弱引用
当map(target,newtarget) 中
如果是Map() 强引用类型 目标对象得到引用 即使是垃圾收回机制不能回收
*/
function deepCopy(target,map = new WeakMap()) {
/* 如果是基本类型 直接拷贝返回 */
if(typeof target !== 'object')
return target
/* 区分数组和对象 还可通过构造器constructor*/
let newtarget = Array.isArray(target) ? [] : {}
if(map.has(target))
return map.get(target)
map.set(target,newtarget)
for(let key in target){
// console.log(key);
/* 对引用类型的深拷贝中 会将Array转化成对象形式 */
newtarget[key] = deepCopy(target[key])
}
return newtarget
}
完整版的策略模式
/**
*
* @param {Object} target
* @param {WeakMap} map
* @returns
*/
function demo(target, map = new WeakMap()) {
/* 原始类型直接返回 */
if (target == null || typeof target != 'object') {
return target
}
/* 对循环引用的设置 */
if (map.has(target)) {
return map.get(target)
}
let newobj
map.set(target, newobj)
/* 策略模式 处理set map boolean date regexp array object function*/
const typeObj = {
Set: (target, map) => {
let newobj = new Set()
target.forEach(item => {
newobj.add(demo(item, map))
})
return newobj
},
Map: (target, map) => {
let newobj = new Map()
target.forEach((item, index) => {
newobj.set(index, demo(item, map))
})
return newobj
},
Boolean: target => {
return new Boolean(target).valueOf
},
Date: target => {
return new date(target).valueof()
},
RegExp: target => {
return new RegExp(target).valueof()
},
Array: (target, map) => {
let newobj = []
target.forEach((item, index) => {
newobj[index] = demo(target[index], map)
})
return newobj
},
Object: (target, map) => {
let newobj = {}
for (let i in target) {
newobj[i] = demo(target[i], map)
}
return newobj
},
Function: target => {
return new target()
}
}
let type = Object.prototype.toString.call(target).slice(8, -1)
if (typeObj && typeObj[type]) {
return (newobj = typeObj[type](target, map))
}
}