小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
本文作为本人学习总结之用,以笔记为主,同时分享给大家.
因为个人技术有限,如果有发现错误或存在疑问之处,欢迎指出或指点!不胜感谢!
对象/数组拷贝
区别浅拷贝与深拷贝
-
纯语言表达:
- 浅拷贝: 只是复制了对象属性或数组元素本身(只是引用地址值)
- 深拷贝: 不仅复制了对象属性或数组元素本身, 还复制了指向的对象(使用递归)
-
举例说明: 拷贝persons数组(多个人对象的数组)
- 浅拷贝: 只是拷贝了每个person对象的引用地址值, 每个person对象只有一份
- 深拷贝: 每个person对象也被复制了一份新的
实现浅拷贝
实现浅拷贝
- 方法一: 利用ES6语法
- 方法二: 利用ES5语法: for...in
/*
*/
/* 方法一: 利用ES6语法*/
function clone1(target) {
// 如果是对象(不是函数, 也就是可能是object对象或者数组)
if (target!=null && typeof target==='object') {
if (target instanceof Array) {
// return target.slice()
// return target.filter(() => true)
// return target.map(item => item)
return [...target]
} else {
// return Object.assign({}, target)
return {...target}
}
}
// 基本类型或者函数, 直接返回
return target
}
/* 方法二: 利用ES5语法: for...in */
function clone2(target) {
if (target!=null && typeof target==='object') {
const cloneTarget = Array.isArray(target) ? [] : {}
for (let key in target) {
if (target.hasOwnProperty(key)) {
cloneTarget[key] = target[key]
}
}
return cloneTarget
} else {
return target
}
}
实现深拷贝
-
实现一: 大众乞丐版
- 问题1: 函数属性会丢失
- 问题2: 循环引用会出错
-
实现二: 面试基础版
- 解决问题1: 函数属性还没丢失
-
实现三: 面试加强版本
- 解决问题2: 循环引用正常
-
实现四: 面试加强版本2(优化遍历性能)
-
数组: while | for | forEach() 优于 for-in | keys()&forEach()
-
对象: for-in 与 keys()&forEach() 差不多
-
/*
1). 大众乞丐版
问题1: 函数属性会丢失
问题2: 循环引用会出错
*/
function deepClone1(target) {
return JSON.parse(JSON.stringify(target))
}
/*
2). 面试基础版本
解决问题1: 函数属性还没丢失
*/
function deepClone2 (target) {
if (target!==null && typeof target==='object') {
const cloneTarget = target instanceof Array ? [] : {}
for (const key in target) {
if (target.hasOwnProperty(key)) {
cloneTarget[key] = deepClone2(target[key])
}
}
return cloneTarget
}
return target
}
/*
3). 面试加强版本
解决问题2: 循环引用正常
*/
function deepClone3 (target, map=new Map()) {
if (target!==null && typeof target==='object') {
// 从缓存容器中读取克隆对象
let cloneTarget = map.get(target)
// 如果存在, 返回前面缓存的克隆对象
if (cloneTarget) {
return cloneTarget
}
// 创建克隆对象(可能是{}或者[])
cloneTarget = target instanceof Array ? [] : {}
// 缓存到map中
map.set(target, cloneTarget)
for (const key in target) {
if (target.hasOwnProperty(key)) {
// 递归调用, 深度克隆对象, 且传入缓存容器map
cloneTarget[key] = deepClone3(target[key], map)
}
}
return cloneTarget
}
return target
}
/*
4). 面试加强版本2(优化遍历性能)
数组: while | for | forEach() 优于 for-in | keys()&forEach()
对象: for-in 与 keys()&forEach() 差不多
*/
function deepClone4 (target, map=new Map()) {
if (target!==null && typeof target==='object') {
// 从缓存容器中读取克隆对象
let cloneTarget = map.get(target)
// 如果存在, 返回前面缓存的克隆对象
if (cloneTarget) {
return cloneTarget
}
// 创建克隆对象(可能是{}或者[])
if (target instanceof Array) {
cloneTarget = []
// 缓存到map中
map.set(target, cloneTarget)
target.forEach((item, index) => {
cloneTarget[index] = deepClone4(item, map)
})
} else {
cloneTarget = {}
// 缓存到map中
map.set(target, cloneTarget)
Object.keys(target).forEach(key => {
cloneTarget[key] = deepClone4(target[key], map)
})
}
return cloneTarget
}
return target
}