npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

fastextend

v1.0.0

Published

Fast recursive object and array clone and merge focused on literal js types. Optimized for v8.

Downloads

45

Readme

Build Status

fastextend

Fast recursive object and array clone and merge focused on literal js types. Optimized for v8.

npm install fastextend

This module is aimed at solving two common use-cases, deep cloning objects/arrays and merging objects and arrays. Many of the current modules suffer from v8 deopts or wonky behaviors regarding arrays, undefined and nested non-literal objects.

Careful work is taken on the internals in order to make sure that we are staying monomorphic and avoiding v8 de-opts according to some of the work by Vyacheslav Egorov. See What's up with monomorphism for more info. This allows us to get 3x to 10x performance over common libraries methods lodash, fast-clone, extend or JSON.parse(JSON.stringify(obj)).

Right now fastextend only works on simple javascript natives, the kind that JSON supports, because attempting to extend/clone non-literal objects is a minefield and causes almost every deep-extend module to have unsolvable edgecases.

cloneable values: {}, [], string, number, boolean, null, undefined.

benchmark

Run the benchmark via npm run simplebench.

As of 8/11/2017 on Node 7.10.1, higher ops/sec is better.

Group:  default
Winner - fastextend.clone

fastextend.clone - count: 176450, ops/sec: 176450
JSON dance - count: 60164, ops/sec: 60164, diff: -65.90%
extend - count: 37990, ops/sec: 37990, diff: -78.47%
fast-clone - count: 29268, ops/sec: 29268, diff: -83.41%
lodash.cloneDeep - count: 18203, ops/sec: 18203, diff: -89.68%

Getting Started

// clone an object
var obj = fastextend.clone({ foo : "fooValue" });

// merge multiple objects
var obj = fastextend.merge({}, { foo : "fooValue" }, { bar : "barValue" });

// deep clone arrays of objects, all nested objects and arrays are cloned
var arr = fastextend.clone([
	{ foo : "fooValue" },
	{ foo : "fooValue2" },
	{ foo : "fooValue3", arr2 : [1,2,3] }
]);

fastextend.clone(obj)

Deep clones an object or an array. The object/array must only contain clonable values. Non-clonable values such as non-literal Objects, Dates or functions will throw.

This is just a shortcut for fastextend.merge({}, obj) or fastextend.merge([], arr).

// deep clones the object to foo
var foo = fastextend.clone({ key : 1, nested : { more : { key2 : true } } });

// deep clones an array of objects, all arrays and objects are cloned
var foo = fastextend.clone([{ foo : 1 }, { foo : 2 }, { foo : 3 }]);

fastextend.merge(target, arg1, arg2, argN);

Clones of each argument are merged into the target object. No interim objects/arrays are modified.

Caveats

  1. You can pass as many objects/arrays and will merge them left to right into the first argument. Nothing but the first argument are modified.
  2. A key with undefined value will overwrite a key with a value. If the key exists it merges.
  3. If the merging key contains an array or object and the target key is neither, it will be overwritten. If the target key matches the type, the subkeys are merged in.
  4. Merging arrays overwrites by key. So fastextend.merge([1,2], [5,2,3], [4]) === [4,2,3].
  5. If merge-key is not clonable, it will throw.

Examples

// merging arrays of objects
fastextend.merge([
	{ id : 1, categories : [{ catid : 1 }] }
], [
	{ categories : [{ added : 1 }] }
])
// result
[
	{ id : 1, categories : [{ catid : 1, added : 1 }] }
]

// merge undefined overwriting key with value
fastextend.merge({ foo : "fooValue" }, { foo : undefined })
// result
{ foo : undefined }

fastextend.mergeWithOptions(target, arg1, arg2, argN, options);

Merge but with the latest argument being options.

  1. options.mergeUndefined - Default true. If true, merges will copy undefined values right to left. So an undefined value will overwrite a value. If set to false, undefined values will not merge.
  2. options.mergeArrays - Default true. If true, it will recurse into arrays and merge keys into those arrays. If false, it treats arrays as simple key, and will only deep clone the right key, but will not merge entries with the left key. In some cases it is desirable that if an array exists in the right key that it simply replaces the array on the left, rather than blends. Setting this to false will accomplish that.
fastextend.mergeWithOptions({ foo : "fooValue" }, { foo : undefined }, { bar : undefined }, { baz : null }, { mergeUndefined : false });
// result
{ foo : "fooValue", baz : null }

fastextend.merge({ foo : "fooValue" }, { foo : undefined }, { bar : undefined }, { baz : null });
{ foo : undefined, bar : undefined, baz : null }

fastextend.mergeWithOptions({ foo : [{ bar : 1 }, { bar : 2 }] }, { foo : [{ baz : 1 }] }, { mergeArrays : false });
{ foo : [{ baz : 1 }] }

fastextend.merge({ foo : [{ bar : 1 }, { bar : 2 }] }, { foo : [{ baz : 1 }] });
{ foo : [{ bar : 1, baz : 1 }, { bar : 2 }] }