strong-tie/inbound-calls
0
1# rfdc2 3Really Fast Deep Clone4 5 6[](https://travis-ci.org/davidmarkclements/rfdc)7[](https://codecov.io/gh/davidmarkclements/rfdc)8[](http://standardjs.com/)9 10 11## Usage12 13```js14const clone = require('rfdc')()15clone({a: 1, b: {c: 2}}) // => {a: 1, b: {c: 2}}16```17 18## API19 20### `require('rfdc')(opts = { proto: false, circles: false, constructorHandlers: [] }) => clone(obj) => obj2`21 22#### `proto` option23 24Copy prototype properties as well as own properties into the new object.25 26It's marginally faster to allow enumerable properties on the prototype27to be copied into the cloned object (not onto it's prototype, directly onto the object).28 29To explain by way of code:30 31```js32require('rfdc')({ proto: false })(Object.create({a: 1})) // => {}33require('rfdc')({ proto: true })(Object.create({a: 1})) // => {a: 1}34```35 36Setting `proto` to `true` will provide an additional 2% performance boost.37 38#### `circles` option39 40Keeping track of circular references will slow down performance with an41additional 25% overhead. Even if an object doesn't have any circular references,42the tracking overhead is the cost. By default if an object with a circular43reference is passed to `rfdc`, it will throw (similar to how `JSON.stringify` \44would throw).45 46Use the `circles` option to detect and preserve circular references in the47object. If performance is important, try removing the circular reference from48the object (set to `undefined`) and then add it back manually after cloning49instead of using this option.50 51#### `constructorHandlers` option52 53Sometimes consumers may want to add custom clone behaviour for particular classes54(for example `RegExp` or `ObjectId`, which aren't supported out-of-the-box).55 56This can be done by passing `constructorHandlers`, which takes an array of tuples,57where the first item is the class to match, and the second item is a function that58takes the input and returns a cloned output:59 60```js61const clone = require('rfdc')({62 constructorHandlers: [63 [RegExp, (o) => new RegExp(o)],64 ]65})66 67clone({r: /foo/}) // => {r: /foo/}68```69 70**NOTE**: For performance reasons, the handlers will only match an instance of the71*exact* class (not a subclass). Subclasses will need to be added separately if they72also need special clone behaviour.73 74### `default` import75It is also possible to directly import the clone function with all options set76to their default:77 78```js79const clone = require("rfdc/default")80clone({a: 1, b: {c: 2}}) // => {a: 1, b: {c: 2}}81```82 83### Types84 85`rfdc` clones all JSON types:86 87* `Object`88* `Array`89* `Number`90* `String`91* `null`92 93With additional support for:94 95* `Date` (copied)96* `undefined` (copied)97* `Buffer` (copied)98* `TypedArray` (copied)99* `Map` (copied)100* `Set` (copied)101* `Function` (referenced)102* `AsyncFunction` (referenced)103* `GeneratorFunction` (referenced)104* `arguments` (copied to a normal object)105 106All other types have output values that match the output107of `JSON.parse(JSON.stringify(o))`.108 109For instance:110 111```js112const rfdc = require('rfdc')()113const err = Error()114err.code = 1115JSON.parse(JSON.stringify(e)) // {code: 1}116rfdc(e) // {code: 1}117 118JSON.parse(JSON.stringify({rx: /foo/})) // {rx: {}}119rfdc({rx: /foo/}) // {rx: {}}120```121 122## Benchmarks123 124```sh125npm run bench126```127 128```129benchDeepCopy*100: 671.675ms130benchLodashCloneDeep*100: 1.574s131benchCloneDeep*100: 936.792ms132benchFastCopy*100: 822.668ms133benchFastestJsonCopy*100: 363.898ms // See note below134benchPlainObjectClone*100: 556.635ms135benchNanoCopy*100: 770.234ms136benchRamdaClone*100: 2.695s137benchJsonParseJsonStringify*100: 2.290s // JSON.parse(JSON.stringify(obj))138benchRfdc*100: 412.818ms139benchRfdcProto*100: 424.076ms140benchRfdcCircles*100: 443.357ms141benchRfdcCirclesProto*100: 465.053ms142```143 144It is true that [fastest-json-copy](https://www.npmjs.com/package/fastest-json-copy) may be faster, BUT it has such huge limitations that it is rarely useful. For example, it treats things like `Date` and `Map` instances the same as empty `{}`. It can't handle circular references. [plain-object-clone](https://www.npmjs.com/package/plain-object-clone) is also really limited in capability.145 146## Tests147 148```sh149npm test150```151 152```153169 passing (342.514ms)154```155 156### Coverage157 158```sh159npm run cov160```161 162```163----------|----------|----------|----------|----------|-------------------|164File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |165----------|----------|----------|----------|----------|-------------------|166All files | 100 | 100 | 100 | 100 | |167 index.js | 100 | 100 | 100 | 100 | |168----------|----------|----------|----------|----------|-------------------|169```170 171### `__proto__` own property copying172 173`rfdc` works the same way as `Object.assign` when it comes to copying `['__proto__']` (e.g. when174an object has an own property key called '__proto__'). It results in the target object 175prototype object being set per the value of the `['__proto__']` own property.176 177For detailed write-up on how a way to handle this security-wise see https://www.fastify.io/docs/latest/Guides/Prototype-Poisoning/.178 179## License180 181MIT182 