Created
January 21, 2020 11:44
-
-
Save bitfishxyz/b5470d59b25c6919abe6b57f6b9e57ac to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function cloneOtherType(target) { | |
const constrFun = target.constructor; | |
switch (toRawType(target)) { | |
case "Boolean": | |
case "Number": | |
case "String": | |
case "Error": | |
case "Date": | |
return new constrFun(target); | |
case "RegExp": | |
return cloneReg(target); | |
case "Symbol": | |
return cloneSymbol(target); | |
case "Function": | |
return target; | |
default: | |
return null; | |
} | |
} | |
function toRawType (value) { | |
let _toString = Object.prototype.toString; | |
let str = _toString.call(value) | |
return str.slice(8, -1) | |
} | |
function cloneSymbol(targe) { | |
return Object(Symbol.prototype.valueOf.call(targe)); | |
} | |
function cloneReg(targe) { | |
const reFlags = /\w*$/; | |
const result = new targe.constructor(targe.source, reFlags.exec(targe)); | |
result.lastIndex = targe.lastIndex; | |
return result; | |
} | |
function forEach(array, iteratee) { | |
let index = -1; | |
const length = array.length; | |
while (++index < length) { | |
iteratee(array[index], index); | |
} | |
return array; | |
} | |
// core function | |
function clone(target, map = new WeakMap()) { | |
// clone primitive types | |
if (typeof target != "object" || target == null) { | |
return target; | |
} | |
const type = toRawType(target); | |
let cloneTarget = null; | |
if (map.get(target)) { | |
return map.get(target); | |
} | |
map.set(target, cloneTarget); | |
if (type != "Set" && type != "Map" && type != "Array" && type != "Object") { | |
return cloneOtherType(target) | |
} | |
// clone Set | |
if (type == "Set") { | |
cloneTarget = new Set(); | |
target.forEach(value => { | |
cloneTarget.add(clone(value, map)); | |
}); | |
return cloneTarget; | |
} | |
// clone Map | |
if (type == "Map") { | |
cloneTarget = new Map(); | |
target.forEach((value, key) => { | |
cloneTarget.set(key, clone(value, map)); | |
}); | |
return cloneTarget; | |
} | |
// clone Array | |
if (type == "Array") { | |
cloneTarget = new Array(); | |
forEach(target, (value, index) => { | |
cloneTarget[index] = clone(value, map); | |
}) | |
} | |
// clone normal Object | |
if (type == "Object") { | |
cloneTarget = new Object(); | |
forEach(Object.keys(target), (key, index) => { | |
cloneTarget[key] = clone(target[key], map); | |
}) | |
} | |
return cloneTarget; | |
} | |
// test | |
const map = new Map(); | |
map.set('key', 'value'); | |
const set = new Set(); | |
set.add('value1'); | |
set.add('value2'); | |
const target = { | |
field1: 1, | |
field2: undefined, | |
field3: { | |
child: 'child' | |
}, | |
field4: [2, 4, 8], | |
empty: null, | |
map, | |
set, | |
bool: new Boolean(true), | |
num: new Number(2), | |
str: new String(2), | |
symbol: Object(Symbol(1)), | |
date: new Date(), | |
reg: /\d+/, | |
error: new Error(), | |
func1: () => { | |
console.log('hello friend!'); | |
}, | |
func2: function (a, b) { | |
return a + b; | |
} | |
}; | |
const result = clone(target); | |
console.log(result); | |
console.log(result.field3 === target.field3) | |
console.log(result.field4 === target.field4) | |
console.log(result.map === target.map) | |
console.log(result.num === target.num) | |
console.log(result.reg === target.reg) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This will fail if an object has a reference to itself:
result.result = result