blitz-copy

2.0.2 • Public • Published

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.

Package Sidebar

Install

npm i blitz-copy

Weekly Downloads

2

Version

2.0.2

License

ISC

Unpacked Size

117 kB

Total Files

18

Last publish

Collaborators

  • markw9