JavsScript 变量包含两种不同数据类型的值: 基本数据类型和引用数据类型,基本数据类型: 标识符-值 存储在栈内存中,引用数据类型: 标识符存在栈内存中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值
浅拷贝
拷贝一层,引用类型数据任然拷贝的是地址的引用
// 1、浅克隆引用对象(利用 es6 扩展运算符),基础类型直接返回
function clone1(target) {
if (typeof target === 'object' && target !== null) {
// 利用 es6 扩展运算符返回容器对象
if (Array.isArray(target)) {
return [...target]
} else {
return { ...target }
}
} else {
return target
}
}
// 2、浅克隆引用对象,返回容器对象,类型类型直接返回
function clone2(target) {
if (typeof target === 'object' && target !== null) {
const result = Array.isArray(target) ? [] : {}
for (const key in target) {
// 判断数据上是否有 key 这个属性
if (target.hasOwnProperty(key)) {
// 将属性压入到 result 容器中
result[key] = target[key]
}
}
return result
} else {
return target
}
}
深拷贝
递归拷贝多层,将引用数据类型解析到基础类型时再进行拷贝
/**
* * 深拷贝(乞丐版),利用 JSON 将数据变成 JSON 格式再根据 JSON 格式创建 JS 数据完成拷贝
* ! 缺点:1、无法拷贝方法;2、无法解决循环引用
*
* @param {*} target
* @return {*}
*/
function deepJsonClone(target) {
// 使用 JS 数据创建 JSON 数据
let str = JSON.stringify(target)
// 使用 JSON 格式数据创建 JS 数据
let data = JSON.parse(str)
return data
// 简写 return JSON.parse(JSON.stringify(target))
}
/**
* * 深拷贝(完整版),在原有基础上提升性能
* ? 数组:while | for | forEach() 优于 for-in | keys()&forEach()
* ? 对象:for-in 与 keys()&forEach() 差不多
*
* @param {*} target
* @return {*}
*/
function deepClone(target, map = new Map()) {
// 判断是否为引用数据类型
if (typeof target === 'object' && target !== null) {
// 判断值是否已被拷贝,如是,则直接返回此值
let cache = map.get(target)
if (cache) {
return cache
}
let isArray = Array.isArray(target)
const result = isArray ? [] : {}
// 创建 map 数据容器以存放用于判断的值
map.set(target, result)
if (isArray) {
target.forEach((item, index) => {
result[index] = deepClone(item, map)
})
} else {
Object.keys(target).forEach((key) => {
result[key] = deepClone(target[key], map)
})
}
return result
} else {
return target
}
}