很多小伙伴面试的时候遇到过手写深拷贝的题目,这篇文章将从基本类型、对象类型、特殊对象类型三种情况出发,实现一个简单的深拷贝函数,让各位小伙伴彻底摆脱深拷贝这个难题,实现代码在最下面,复制下来所有的函数代码可直接运行。
针对不同的值的拷贝方式
基本类型
- Null
- Number
- Boolean
- String
- Undefined
any => any
对象类型
any => {
// 创建一个普通对象
const o = new Object()
// 复制any所有的属性到o上,实现方式在下面
copyOwnProperties(any, o)
return o
}
特殊的对象类型
日期类型
any => new Date(any)
正则类型
any => new Regex(any)
函数类型
any => {
// 创建一个函数对象
const o = new Function("return " + any.toString())()
// 复制any所有的属性到o上,实现方式在下面
copyOwnProperties(any, o)
return o
}
数组类型
any => {
// 创建一个数组对象
const o = new Array()
// 复制any所有的属性到o上,实现方式在下面
copyOwnProperties(any, o)
return o
}
实现一个完整的深拷贝函数
TypeOf
// 获取数据类型
function typeOf(any) {
return Object.prototype.toString.call(any).split(' ')[1].slice(0, -1)
}
copyOwnProperties
// 复制from的属性到to上,cache保存已复制属性引用,防止重复引用
function copyOwnProperties(from, to, cache) {
const names = Object.getOwnPropertyNames(from)
for (let name of names) {
const descriptor = Object.getOwnPropertyDescriptor(from, name)
Object.defineProperty(to, name, { ...descriptor, value: recursionClone(descriptor.value, cache) })
}
return to
}
recursionClone
// 根据不同类型的数据进行不同的拷贝方式,cache保存已复制属性引用,防止重复引用
function recursionClone(any, cache) {
const typ = typeOf(any)
if (['String', 'Number', 'Null', 'Boolean', 'Undefined'].includes(typ)) {
return any
}
if (!cache) {
cache = new Map()
}
if (cache.get(any)) {
return cache.get(any)
}
if (typ === 'RegExp') {
return new RegExp(any)
}
if (typ === 'Date') {
return new Date(any)
}
let O
if (typ === 'Function') {
O = (new Function('return ' + any.toString()))()
}
if (typ === 'Array') {
O = new Array()
}
if (typ === 'Object') {
O = new Object()
}
if (O) {
cache.set(any, O)
copyOwnProperties(any, O, cache)
return O
}
return null
}
deepClone
function deepClone(any) {
return recursionClone(any)
}
总结
- 基本类型直接拷贝
- 对象类型递归拷贝,缓存已拷贝值,防止互相引用
- Function、Array、Date、Regex类型进行特殊处理