UNPKG

@jsbits/deep-clone

Version:

Performs a deep cloning of an object own properties and symbols, with loosy or exact behavior.

202 lines (199 loc) 6.1 kB
/* @jsbits/deep-clone @author aMarCruz @version 1.1.1 ESM+ES6 @license MIT */ /* eslint-disable */ const _nodejs = (function () { const g = typeof global === 'object' && global; const m = g && g.process && typeof g.Buffer === 'function' && /^v?(\d+)/.exec(g.process.version); return (m && m[1]) | 0; })(); const _OP = Object.prototype; const _toString = _OP.toString; const _ownKeys = typeof Reflect === 'object' && typeof Reflect.ownKeys === 'function' && Reflect.ownKeys; const clonable = { Date: 1 , RegExp: 1 , String: 1 , Number: 1 , Boolean: 1 , Float32Array: 1 , Float64Array: 1 , Int8Array: 1 , Int16Array: 1 , Int32Array: 1 , Uint8Array: 1 , Uint8ClampedArray: 1 , Uint16Array: 1 , Uint32Array: 1 , Array: 2 , ArrayBuffer: 3 , SharedArrayBuffer: 3 , DataView: 4 , Error: 6 , Map: 5 , Set: 5 , Arguments: 7 , Atomics: 8 , JSON: 8 , Math: 8 , Promise: 8 , WeakMap: 8 , WeakSet: 8 , XMLHttpRequest: 8 , }; const arrayLike = [ 'Array', 'String', 'Float32Array', 'Float64Array', 'Int8Array', 'Int16Array', 'Int32Array', 'Uint8Array', 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', ]; const getKeyGetter = function (exact) { const _keys = exact ? Object.getOwnPropertyNames : Object.keys; const _getSymbols = Object.getOwnPropertySymbols; if (!_getSymbols) { return _keys; } if (exact) { return (obj) => _keys(obj).concat(_getSymbols(obj)); } const _isEnum = _OP.propertyIsEnumerable; return (obj) => { const objkeys = _keys(obj); const symbols = _getSymbols(obj); for (let i = 0; i < symbols.length; i++) { if (_isEnum.call(obj, symbols[i])) { objkeys.push(symbols[i]); } } return objkeys; }; }; const getKeysFac = function (exact) { const _filtIdx = (prop) => prop !== '0' && (prop | 0) <= 0 && prop !== 'length'; const _getKeys = exact && _ownKeys || getKeyGetter(exact); return (obj, type) => { const objkeys = _getKeys(obj); return ~arrayLike.indexOf(type) ? objkeys.filter(_filtIdx) : objkeys; }; }; const cloneMapOrSet = (src, fn, type) => { const dest = new src.constructor(); const cb = type === 'Set' ? function (v) { this.add(fn(v)); } : function (v, k) { this.set(fn(k), fn(v)); }; src.forEach(cb, dest); return dest; }; const cloneDataView = (src) => { const buffer = src.buffer.slice(0); return new src.constructor(buffer, src.byteOffset, src.byteLength); }; const cloneError = (src) => { const err = new src.constructor(src.message); return Object.defineProperty(err, 'stack', { value: src.stack, configurable: true, writable: true, }); }; const cloneArguments = (src) => { const args = Object.create(null); return Object.defineProperty(args, 'length', { value: src.length, configurable: true, writable: true, }); }; const cloneArray = (src, fn) => src.map(fn); const cloneFn = { [8 ]: (obj) => obj, [7 ]: cloneArguments, [2 ]: cloneArray, [3 ]: (obj) => obj.slice(0), [4 ]: cloneDataView, [6 ]: cloneError, [5 ]: cloneMapOrSet, }; const createObject = (obj, type, fn) => { const cloneType = clonable[type]; if (cloneType === 1 ) { return obj.slice && _nodejs && Buffer.isBuffer(obj) ? obj.slice(0) : new obj.constructor(obj.valueOf()); } if (cloneFn[cloneType]) { return cloneFn[cloneType](obj, fn, type); } return type.lastIndexOf(' Iterator', type.length - 9) > -1 ? obj : Object.create(Object.getPrototypeOf(obj)); }; const getObjectType = (function () { const _getTag = (obj) => _toString.call(obj).slice(8, -1); if (!_nodejs || _nodejs >= 5) { return _getTag; } return (obj) => { const tag = _getTag(obj); return tag === 'Object' && obj.constructor && obj.constructor.name === 'Promise' ? 'Promise' : tag; }; })(); const cloneFac = function (getKeys) { const _clone = function _clone(obj) { if (!obj || typeof obj !== 'object') { return obj; } const type = getObjectType(obj); const clone = createObject(obj, type, _clone); const props = getKeys(obj, type); for (let i = 0; i < props.length; i++) { const prop = props[i]; const desc = Object.getOwnPropertyDescriptor(obj, prop); if (desc.value !== undefined) { desc.value = _clone(obj[prop]); } Object.defineProperty(clone, prop, desc); } return clone; }; return _clone; }; const looseClone = cloneFac(getKeysFac(false)); const exactClone = cloneFac(getKeysFac(true)); /** * Performs a deep cloning of an object own properties and symbols, preserving * its prototype. * * By default `cloneObject` works in "loosy mode", where it clones only * the object _enumerable_ properties and symbols. * * To enable the "exact mode" and clone all, pass `true` in the second parameter. * * Both modes retain all the attributes of the copied properties (enumerable, * configurable, writable) and correctly transfer the `get` and/or `set` * methods, although these, like the other function-type values, * _are copied by reference_. * * Try to limit the usage of this function to POJOs, as this function does not * work for objects with constructor that requires parameters (other than * the most JS built-in Objects), nor objects with recursive references. * * @template T * @param {T} value Value to clone, mostly an object or array. * @param {boolean} [exact=false] If `true`, also clone the non-enumerable properties * @returns {T} The cloned object or value. * @since 1.0.0 */ const deepClone = function _deepClone(value, exact) { return exact ? exactClone(value) : looseClone(value); }; export default deepClone; //# sourceMappingURL=index.mjs.map