objutil
v2.17.4
Published
Javascript Object util with deep traverse, support ES6 tree shaking methods: get/set/unset/remove object path, visit, assign(extend), merge, remove, defaults, pick, filter, forEach, map, some, every, isEqual. Customize the APIs into one file.
Downloads
298
Readme
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.
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
- 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 VSobjutil version
: 0.7KB!
- 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:
Install rollup:
npm install -g rollup
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 onlyset
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)