blitz-copy
v2.0.2
Published
Ultra fast ES6 deep copier.
Downloads
8
Maintainers
Readme
blitz-copy 2.0.1
This package provides deep copiers that handle all ES6 = ECMA-2015 data types, and supplies NPM's fastest deep copiers, but see the Speed section for caveats.
Currently, blitz-copy, and the author's deep-copy-system are the only true deep copier packages that are correct, as defined by this packages small test suite. However, a shout-out to true-clone, which is fully correct except for an obscure issue that previous versions of blitz-copy and deep-system-copy also missed.
Exports
|export|description|
|---|---|
|blitzCopy(x)| Equivalent to blitzCopyExt(x, {cd:true})
|
|blitzCopyExt(x, params)| has parameters for describing what is to be copied |
|||
|||
|params fields|description (all fields if unspecified default to false)|
|cd| If true, all circular and duplicate references are copied|
|pd| If true, property descriptors are copied|
|freeze| If true, frozen/sealed/extensible states are copied|
|allProperties|If true, properties come from Object.getOwnPropertyNames. Otherwise from Object.keys the former gives all properties, the latter only the enumerable ones|
|deepFreeze|For functional programmers who like their deep copies deep-frozen, set params.deepFreeze
to true
.|
|warn_indices_config| If true gives warning that indices of Arrays may be reconfigured (array is whacked)|
|warn_array_extras|If true gives warning that Arrays have been given extra non-index properties (array is whacked)|
So blitzCopyExt()
is highly configurable, and you can create your own wrapper around it to set
the properties you are most interested in. So for example true-clone and fast-copy would be equivalent to
function likeTrueClone(x)
{
return blitzCopyExt(x, {cd:true, pd:true, warn_indices_config:true,
warn_array_extras:true})
}
function likeFastCopy(x)
{
return blitzCopyExt(x, {cd:true})
}
Set cd
, pd
, allProperties
, warn_indices_config
, and warn_array_extras
to false/unspecified
whenever possible for significant speed gains. So blitzCopyExt(x)
with no parameters specified
is fastest.
Usage
npm install blitz-coopy
const {blitzCopy, blitzCopyExt} = require('blitz-copy')
x = complicated object built from plain objects, secondary objects,
and ES6 data types.
const y = blitzCopy(x) // y is deep copy of x
x = complicated object built from plain objects, secondary objects,
and ES6 data types.
const y = blitzCopy(x, {cd:false, pd:true, freezers:true,
allProperties:true, warn_indices_config:true}
/* Explanation of Parameters:
cd:false -> CD (circular/duplicate) references are not handled
because one is sure that there are no such references.
pd:true -> PDs (property descriptors) are copied.
freezers:true -> Frozen/sealed/extensible states are copied.
deepFreeze:unspecified -> y will not be deep frozen
unless x is.
allProperties:true -> All properties, not just the enumerable
ones, are copied.
warn_indices_config:true -> gives warning that indices of
arrays/typed arrays may have been reconfigured.
warn_array_extras:unspecified -> there are no array
extras.
*/
A secondary object is an object created with Object.create().
Complicated for example means Booleans can have DataView properties, Sets can have members that are Maps and DataViews. Maps can have keys that are ArrayBufers, and TypedArrays, while having values that are Maps, Sets... whatever. The ends of circular or duplicate references can be the keys of Sets, or the keys and values of Maps
WeakSets, and WeakMaps are copy primitives, meaning copied as is since the programmer can't read their internal states. Promises are also copied as is.
Getters/Setters
If you want to copy getters/setters, then you must set params.pd
to true
because getters/setters
are copied by copying property descriptors. If your getter/setter
is not inlined but rather created with Object.defineProperty(), Object.defineProperties, or Object.create()
where the enumerable flag is not set to true
, then you must also set params.allProperties
to true
to ensure that properties come from Object.getOwnPropertyNames
.
Speed
Currently, no other deep copier copies DataViews and Typed Arrays correctly: this includes previous versions of blitz-copy. It's tricky because you have to take into account that their buffers may be shared amongst themselves resulting in circular/duplicate array buffer references: these circular/duplicate references must themselves be copied. The correctness of blitzCopy() slows down the function so that blitzCopy() may be slower than a competitor when only typed arrays and data views are involved.
When Error classes are involved, some competitors may be faster because they don't actually copy the errors, but rather copy as is: Calling an Error class constructor is very-very-super expensive because it traces the call stack.
Copiers in review
Out of thirty-five copying packages examined, only eleven are deep copiers that
supposedly handle ES6 data types. Some by design do not copy properties of
the data-types and so are more like JSON deep copiers. E.g., if x
is a Set and
x.a = 7
then x.a
is not copied because it is not examined. With the authors
particular design in mind, nine are so buggy they aren't in the ball-park. The two
exceptions are true-clone and fast-copy.
The second most correct true deep-copier package on NPM is true-clone. Except for blitz-copy, true-clone is the only package that passes this packages small test suite with flying colors. However, it doesn't deal with DataViews and Typed arrays correctly as described in the previous section. When data views and typed arrays are not involved, blitz-copy can be 27% faster.
The third most correct deep copier is fast-copy, though it is not a true deep copier
because it is not designed to copy properties of data-types. Even so, without typed arrays involved,
blitz-copy can still be faster: 11% faster is typical. fast-copy is not fully correct
with its design in mind. If x = new String("cat")
then fast copying x
results
in y
where y.valueOf()
isn't "cat"
but rather to the empty string ""
.
The fast copy of new Number(7)
has valueOf equal to 0
not 7
. Those are the
only two bugs found in fast-copy other than dealing with typed-arrays/data-views
as previously described.
Lastly an Example
const x = [1,2,3];
Object.defineProperty(x, "hamster", {
value: "piper"
});
const z = blitzCopyExt(x, {warn_array_extras:true,
pd:true, allProperties:true,});
In the object tree:
there is a non-index property "hamster" on an array
or typed array. so warn_array_extras must be set to true.
there is a property descriptor "hamster so pd must be true.
there is a non-enumerable property "hamster" so allProperties
must be set to true.
Version History
|Version| Published|Description|
|---|---|---|
|1.0.0|3-27-2022|Derived from deep-copy-system for speed without the need to deep-copy ES5 and ES6 classes|
|1.0.1| 3-28-2022|Rewrote code in the ReadMe file so the scroll bar wouldn't appear |
|1.0.2 |3-28-2022|Edited the ReadMe file |
|1.1.0 |3-31-2022|Client can now set params.nonStandardArrays = true
to warn of non-standard arrays/typed-arrays. Not setting it, if possible, results in significant speed gains.|
|2.0.0|4-1-2022|The nonStandardArrays
property has been replaced with two properties warn_config_indices
and warn_array_extras
. If it is possible to set these last two to false
there can be significant speed gains.|
|2.0.1|5-6-2022|Fixed: didn't take into account the fact that array buffers can be shared amongst data views and typed arrays. This results in a slowdown, but blitzCopy() is still fastest.|