1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
| const TYPE_OBJECT = '[object Object]'; const TYPE_MAP = '[object Map]'; const TYPE_SET = '[object Set]'; const TYPE_ARRAY = '[object Array]'; const TYPE_ARGUMENTS = '[object Arguments]'; const TYPE_BOOLEAN = '[object Boolean]'; const TYPE_DATE = '[object Date]'; const TYPE_NUMBER = '[object Number]'; const TYPE_STRING = '[object String]'; const TYPE_SYMBOL = '[object Symbol]'; const TYPE_ERROR = '[object Error]'; const TYPE_REGEXP = '[object RegExp]'; const TYPE_FUNCTION = '[object Function]'; const TYPE_UNDEFINED = '[object Undefined]';
const forEach = (array, iterator) => { let index = -1; let length = array.length; while(++index < length) { iterator(array[index], index); } return array; }
const isObj = (value) => { const type = typeof value; return value !== null && (type === 'object' || type === 'function'); }
const getType = (value) => { return Object.prototype.toString.call(value); }
const canCopyTags = [TYPE_OBJECT, TYPE_ARRAY, TYPE_MAP, TYPE_SET, TYPE_ARGUMENTS];
const getInit = (value) => { const ctor = value.constructor; return new ctor(); }
const copyReg = (value) => { const regFlags = /\w*$/; const newReg = new value.constructor(value.source, regFlags.exec(value)); newReg.lastIndex = value.lastIndex; return newReg; }
const copySymbol = (value) => { return Object(Symbol.prototype.valueOf.call(value)); }
const copyFunction = (value) => { const bodyReg = /(?<={)(.|\n)+(?=})/m; const paramReg = /(?<=\().+(?=\)\s+{)/; if (value.prototype) { const body = bodyReg.exec(value.toString()); const param = paramReg.exec(value.toString()); if (body) { if (param) { const paramArr = param[0].split(','); return new Function(...paramArr, body[0]); } else { return new Function(body[0]); } } else { return null; } } else { return eval(value.toString()); } }
const copyOther = (value, type) => { const ctor = value.constructor; switch(type) { case TYPE_BOOLEAN: case TYPE_NUMBER: case TYPE_STRING: case TYPE_ERROR: case TYPE_DATE: return new ctor(value); break; case TYPE_REGEXP: return copyReg(value); break; case TYPE_SYMBOL: return copySymbol(value); break; case TYPE_FUNCTION: return copyFunction(value); break; default: return null; } }
const copy = (origin, relationMap = new WeakMap()) => { if (!isObj(origin)) return origin;
const type = getType(origin); let target; if (canCopyTags.includes(type)) { target = getInit(origin); } else { return copyOther(origin, type); }
if (relationMap.get(origin)) return relationMap.get(origin); relationMap.set(origin, target);
if (type === TYPE_SET) { origin.forEach((value) => { target.add(copy(value)); }); return target; }
if (type === TYPE_MAP) { origin.forEach((value, key) => { target.set(key, copy(value)); }); return target; }
const keys = type === TYPE_ARRAY ? undefined : Object.keys(origin); forEach(keys || origin, (value, key) => { if (keys) { key = value; } target[key] = copy(origin[key], relationMap); });
return target; }
const originObj = { name: 'Trump', age: 94, phone: undefined, idNo: Symbol('1900'), speak: () => console.log('I am Trump'), [Symbol.for('weight')]: 120, team: { leader: 'Ywank', office: { address: 'white house' } }, employee: [ { name: 'pense', }, { name: 'fox', }, ], }
originObj.president = originObj;
console.log(copy(1)); console.log(copy(undefined)); console.log(copy(/\d/)); console.log(copy(new Date()));
const someFun = function(num1, num2) { console.log(num1 + num2); return num1 + num2; }
const copyFun = copy(someFun); console.log(copyFun(1, 3));
const someSet = new Set(); someSet.add(1); console.log(copy(someSet));
const copyObj = copy(originObj); console.log(originObj); console.log(copyObj); copyObj.speak();
|