针对每一种数据类型作特殊处理:
简单数据类型、null、undefined:返回本身即可Array Map、Set:对每一项元素作递归处理,最后返回Date:返回new Date(+o),+o相当于o.getTime()返回的是时间戳RegExp:返回new RegExp(o)Object:对每一个非继承属性作递归处理,最后返回
function deepClone(o, visited = new WeakMap()) {
// 简单数据类型、null、undefined
if (typeof o != 'object' || o == null) return o
if (visited.has(o)) return visited.get(o) // 处理循环引用的情况
// Array:五种数组判断方法,总有一款适合你
if (
Array.isArray(o) ||
o instanceof Array ||
o.__proto__ === Array.prototype ||
o.__proto__.constructor === Array ||
Object.prototype.toString.call(o).slice(8, -1) === 'Array'
) {
let ret = []
visited.set(o, ret)
for (let i = 0; i < arr.length; i++) ret.push(deepClone(arr[i], visited))
return ret
}
// Date
if (o instanceof Date) return new Date(+o)
// RegExp
if (o instanceof RegExp) return new RegExp(o)
// Map
if (o instanceof Map) {
let ret = new Map()
visited.set(o, ret)
for (let [key, val] of o) ret.set(key, deepClone(val, visited))
return ret
}
// Set
if (o instanceof Set) {
let ret = new Set()
visited.set(o, ret)
for (let val of Set) ret.add(deepClone(val, visited))
}
// Object
let ret = {}
visited.set(o, ret)
for (let key in o) {
if (!o.hasOwnProperty(key)) continue // 跳过原型属性
ret[key] = deepClone(o[key])
}
return ret
}
考虑到会有循环引用的情况如: let b = { a }; let a = { b },对于对象类型属性加一个weakMap来记录是否访问过即visited.set(o, ret),若已访问过直接return visited.get(o)