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.
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
- 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 }
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
- NPM
npm install objutil
- Browser
<script src="https://unpkg.com/objutil"></script>
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)
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 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]
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 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
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 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
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
}
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'
}
}
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
}
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
}
}
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
}
}
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'])
deeply compare objA and objB for equality
isEqual( {a:1, b:2}, {a:1, b:2 } )
//result=> true
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'
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']
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
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
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)