objutil

2.17.4 • Public • Published

objutil

Javascript Object util methods with deep traverse, with ES6 tree shaking methods: get/set/unset/remove object path, visit, assign(extend), merge, remove, defaults, pick, filter, isEqual. Customize the APIs into one file.

Build Status Coverage Status npm

Why?

Compared with Array, javascript missing the Object utils, think Array.prototype.filter, Array.prototype.map conterpart of Object

Unlike lodash, objutil only provide methods for Object, like Object.pick, Object.defaults, Object.get etc, small and customizable

Features

  1. Small, dynamically generate API using tree shaking to select only the methods you want, remove unused code for size optimization

lodash, _.assign and _.defaults: 31KB VS objutil version: 0.7KB!

  1. Deep by default: all methods is deeply operation, like below:
pick(
    { a:2, b:{c:3, e:5}, d:4 },  //src object
    { b:{c:1}, d:1 }   // selection
)
// => { b:{c:3}, d:4 }

How?

If you don't need dynamically generate API, all methods is out of box, nothing needed.

If you need generate API for yourself, do below:

  1. Install rollup: npm install -g rollup

  2. Select the API by below command line:

rollup -c --api assign,defaults
rollup -c --api 'isPrimitive as isP, isIterable as isT'
// then use objutil.isP as `isPrimitive`, etc.

Or add below line in your npm scripts of package.json:

scripts: {
  ...
  "objutil": "rollup -c ./node_modules/objutil/rollup.config.js --api assign,pick"
}

This will tree shake the lib, leave only objutil.assign, objutil.defaults methods

Install

  • NPM
npm install objutil
  • Browser
<script src="https://unpkg.com/objutil"></script>

Quick Start:

Think below initial vars:

var a = {
  x:1,
  y:{
    w:1,
    z:2
  }
}

var b= {
  y:{
    z:10,
    u:'name'
  }
}

Use with objutil:

var {merge, remove} = require('objutil')
merge(a,b)
remove(a,b)

API

visit( obj, fn )

Visit each obj node (key:value pair), with fn({val, key, path, col})

val & key is current value and key pair

path is the current object path for the key,

col is the current collection object

[] indicate the root path, ['a', 'b'] is the path of node x:1 in { a: { b: {x:1} } }

visit( {a:2, b:{c:3}}, (v) => console.log(v.key, v.val, v.path) )

// prints
a 2 []
b {c:3} []
c 3 ['b']

get( obj, pathArray, isThrow )

Get object value from pathArray. When not found, throw error if isThrow is true, else return [undefined, 1]

The result, if NOT isThrow, is the form: [data, errorCode], errorCode===1, indicate: not found.

If path exists, return [data], indicate no error.

If isThrow, return data when found, return Error('NotFound') when not found.

get( a, ['y', 'z'] )

//result is
[2]

//throw error when not found
get(a, ['x', 'y'], true)

//return with error code
get(a, ['x', 'y'])
[undefined, 1]

got( obj, propArray, defaultValue )

Search each path in propArray, return first value found, or defaultValue if none found.

Where you can use get, you can use got, which also give you fallback into different path and defaultValue.

got( {prop: {value: 1}}, ['prop1', 'prop2'], 3 )

//result is
3

got( {prop: {value: 1}}, 'prop.value' )

//result is
1

set( obj, pathArray, value, descriptor )

Set object value from pathArray. When there's non-object in the path, throw error, return the final object

Set pathArray in obj to value, when the path not exist or all the intermediate is object.

When descriptor is object, will modify the prop according Object.defineProperty

When found non-object value in intermediate, throw Error('cannot set non-object path')

set( {}, ['y', 'z'], 23 )

//result is
{ y: { z: 23 } }

// but below will return Error object
set( { y:1 }, ['y', 'z'], 23 )
//result is
Error('cannot set non-object path')

set( {}, 'a', 2, {e:0, w:0, c:1} )

{a:2}  // a is configurable, but not enumerable and writable

OR:

set( {}, 'a', 2, {configurable:false, enumerable:false, writable:false} )

OR SAME AS ABOVE:

set( {}, 'a', 2, {} )

{a:2}  // a is not configurable, enumerable and writable

ensure( obj, pathArray, defaultValue )

Like set, but only set when pathArray not exists

Set pathArray in obj to defaultValue, only when path not exists.

Return undefined if path exists, and do nothing, else return obj

obj = ensure( {}, ['y', 'z'], 1 )

//result is
obj = { y: { z: 1 } }

ret = ensure( obj, ['y', 'z'], 2 )
// ret===undefined
// obj==={ y: { z: 1 } }
// obj unchanged

unset( obj, pathArray )

Unset object value from pathArray. When there's non-object in the path, return undefined, or true/false as result

unset( {prop: {value: 1}}, 'prop.value' )

//result is
true

assign( obj, ...args )

Shallow assign args properties into obj, from left to right order.

Roughly equal to lodash.assign and Object.assign

assign( a, b, {w:3} )

//result=>
{
  x:1,
  y:{
    z:10,
    u:'name'
  },
  w:3
}

merge( obj, ...args )

Deeply merge args properties into obj, from left to right order.

Roughly equal to lodash.merge

merge( a, b, {y:{v:3}} )

//result=>
{
  x:1,
  y:{
    v:3,
    w:1,
    z:10,
    u:'name'
  }
}

defaults( obj, ...args )

deeply merge args key/val into obj, left to right, only when it's not existing in obj

Roughly equal to lodash.defaultsDeep (deeply lodash.defaults)

defaults( {}, {a:1}, {a:2, b:5 } )

//result=>
{
  a:1,
  b:5
}

remove( obj, removeObj, [force] )

Deeply delete removeObj(if force or key has a truthy value) from obj, optionally set to newValue if present

remove( a, { y:{z:true} } )

//result=>
{
  x:1,
  y:{
    w:1
  }
}

pick( obj, pickObject, force)

Like remove, but return the reversed new object(not mutate obj). Deeply keep from pickObject (if force or key has a truthy value) from obj

If obj is primitive types, then always return {}

pick( a, {x:true, y:{z:true} } )

//result=>
{
  x:1,
  y:{
    z:2
  }
}

filter( obj, predicate)

return array of key path(dot notation) that passed predicate

predicate: fn({val, key, path, col}) -> true/false

expect(lib.filter({a:1, b:{c:2, d:3}, e:4}, function(v) {
  return v.path=='' && v.val % 2
})).deep.eql(['a'])

isEqual( objA, objB )

deeply compare objA and objB for equality

isEqual( {a:1, b:2}, {a:1, b:2 } )

//result=> true

forEach( obj, callback )

callback: fn(value, key, obj) -> false?, return false will exit iteration

forEach( {a:1, b:2}, function(val, key){ console.log(val, key) } )

// 1, 'a'
// 2, 'b'

map( obj, callback )

callback: fn(value, key, obj) -> val, return array of val

Like Array.prototype.map does for Object

map( {a:1, b:2}, (val, key)=>key+val )

['a1', 'b2']

some( obj, callback )

callback: fn(value, key, obj) -> true/false, return true/false

Like Array.prototype.some does for Object

some( {a:1, b:2}, (val, key)=>val>1 )

true

every( obj, callback )

callback: fn(value, key, obj) -> true/false, return true/false

Like Array.prototype.every does for Object

every( {a:1, b:2}, (val, key)=>val>1 )

false

deepIt( a, b, callback )

Iterate b with deeply sync props of a, and callback(objA, objB, key)

deepIt( a, b, function(objA,objB,key){
    objA[key] = objB[key]
} )
// ---> same result of assign(a,b)

MIT

Package Sidebar

Install

npm i objutil

Weekly Downloads

55

Version

2.17.4

License

MIT

Unpacked Size

1.08 MB

Total Files

17

Last publish

Collaborators

  • mithriljs_cn
  • cssobj