function deep_copy(src) {
const type = src === null ? '' : Object.prototype.toString.call(src)
const method = getCopyMethod(type)
return method(src)
}
function getCopyMethod(type) {
let method
function copyObject (src) {
const target = Object.create(Reflect.getPrototypeOf(src))
Reflect.ownKeys(src).forEach(key => {
target[key] = deep_copy(src[key])
})
return target
}
function copyArray(src) {
const target = Array(src.length)
src.forEach((item, index) => {
target[index] = deep_copy(item)
})
return target
}
function copyMap(src) {
const target = new Map()
for (let [ key, value ] of src.entries()) {
target.set(key, deep_copy(value))
}
return target
}
function copySet(src) {
const target = new Set()
for (let value of src.values()) {
target.add(deep_copy(value))
}
return target
}
function copyOther(src) {
let target = src
if (typeof src === 'object') {
if (type === '[object Number]') {
target = new Number(src.valueOf())
} else if (type === '[object String]') {
target = new String(src.valueOf())
} else if (type === '[object Boolean]') {
target = new Boolean(src.valueOf())
}
}
return target
}
switch (type) {
case '[object Object]' :
method = copyObject
break
case '[object Array]' :
method = copyArray
break
case '[object Map]' :
method = copyMap
break
case '[object Set]' :
method = copySet
break
default :
method = copyOther
}
return method
}