deep-key
v0.9.9
Published
Similar to key of object (Object.keys) but deep key. Provides recursive access to object member.
Downloads
6
Maintainers
Readme
deep-key
"Deep Key" is single dimentional array of keys that represents full path of object member. Similar to key of object (Object.keys) but "deep" key. Provides recursive access to object member.
const DeepKey = require('deep-key');
var obj = { p1: { p2: { p3: { p4: 0 } } } };
DeepKey.keys(obj);
// [ ['p1'], ['p1', 'p2'], ['p1', 'p2', 'p3'] ... ]
Install
npm install --save deep-key
Functions
keys
Get all deep keys recursively. Many options are available. See Options.
DeepKey.keys(obj);
DeepKey.keys(obj, option);
get
Get value of object member that is pointed by deep key.
DeepKey.get(obj, deepkey);
set
Set value for object member that is pointed by deep key.
DeepKey.set(obj, deepkey, value);
Whether such a member exits or not, member is always overwritten or created. To
prevent this, use exists
to check its existence.
touch
Create object member that is pointed by deep key if does not exist. Similar to
set
method, but value never be changed if member already exist.
For initial value of new member, third argument value
is used if present,
otherwise undefined
is used.
DeepKey.touch(obj, deepkey);
DeepKey.touch(obj, deepkey, value);
Returns value of object member.
type
Get type of object member that is pointed by deep key.
If member does not exist, return "undefined"
.
Note that typeof(null)
returns "object"
.
DeepKey.type(obj, deepkey);
// equivalent with
// typeof(DeepKey.get(obj, deepkey))
accessor
Get accessor of object member that is pointed by deep key.
Accessor has get
and set
methods.
DeepKey.accessor(obj, deepkey);
Caching accessor may be able to reduce computing cost that relates with object tree traversing.
If there are no member that is pointed by deep key, member is automatically
created. (Initial value is undefined
).
delete
Remove object member that is pointed by deep key.
Equivalent to using delete
keyword.
DeepKey.delete(obj, deepkey);
Returns value of object member that is pointed by deep key.
rename
Rename key of object member by using current and new deep keys.
DeepKey.rename(obj, src, dest);
If member that is pointed by src
does not exist, undefined
is set for one of
dest
. And, whether one of dest
already exists or not, it will be overwritten
by one of src
. To prevent those, use exists
to check their existence.
Returns value of object member that is pointed by deep key.
exists
Check existence of object member that is pointed by deep key.
DeepKey.exists(obj, deepkey);
Options
The following options are available for keys().
all
all
option allows to get all member enumeration including unenumerable members.
var obj = { enum: 'e', };
Object.defineProperty(obj, 'unenum', { value: 'u' });
obj.propertyIsEnumerable('unenum');
// false
DeepKeys.keys(obj);
// [ ['enum'] ]
DeepKeys.keys(obj, { all: true });
// [ ['enum'], ['unenum'] ]
depth
depth
option allows to limit enumeration by depth.
var obj = { prop1: { prop2: { prop3: { } } } }
console.log(DeepKey.keys(obj, { depth: 2 }));
// [ ['prop1'], ['prop1', 'prop2'] ]
If merely want to specify depth
option, can directly pass into second argument
in place of option
.
DeepKey.keys(obj, depth);
Note that all keys will be enumerated if zero or negative value is specified for
depth
.
filter
filter
option allows to limit enumeration by your custom function.
var obj = {
prop1: { prop2: {} }
prop3: { skip1: {} },
prop4: 'p4',
skip2: 'e2'
}
console.log(DeepKey.keys(obj, {
filter: (deepkey, value) => {
return !/skip\d+/.test(deepkey.join('.'));
}
});
// [ ['prop1'], ['prop1', 'prop2'], ['prop3'], ['prop4'] ]
For each member, filter
function is called back by passing the following three arguments:
deepkey
: deep key of membervalue
: value of member that is pointed bydeepkey
enumerable
: whether member is enumerable (propertyIsEnumerable
)
filter
function must return true
in order to include in enumeration,
false
otherwise.
If merely want to specify filter
option, can directly pass into second
argument in place of option
.
DeepKey.keys(obj, filter);
noindex
noindex
option allows to suppress index-enumeration of Array
.
In JavaScript world, Array
is also object-type and its indexes are keys
of object.
An Array object is an exotic object that gives special treatment to array index property keys (ES6 9.4.2)
Try the following code:
typeof [];
// 'object'
Object.keys(['one', 'two', 'three']);
// [ '0', '1', '2' ]
Therefore, keys
of this package also enumerate keys of Array
by default.
In most case, this behavior is an undesirable overboundance.
noindex
option can suppress this.
NOTE: Array
is also extensible. Note that its extended member will be
always enumerated, regardless of noindex
option.
var obj = { array: [1,2,3], val: 4 };
obj.array.five = 5;
DeepKey.keys(obj, { noindex: true });
// [ ['array'], ['array', 'five'], ['val'] ]
leaf
leaf
option allows to enumerate only "leafs" that have no descendant keys:
DeepKeys.keys({a: {b: {c: 'd'}}}, {leaf: true});
// [ ['a', 'b', 'c', 'd'] ]
When Array members are present, noindex
is recommended in most cases.
DeepKeys.keys({a: ['b', 'c']}, {leaf: true});
// [ ['a', '0'], ['a', '1'] ]
// In most cases, maybe indexes are not expected "leafs".
DeepKeys.keys({a: ['b', 'c']}, {leaf: true, noindex: true});
// [ ['a'] ]
Finally, the behavior both leaf
and depth
options are specified is
cautionable. It will return pseudo-leafs under the restriction of specified
depth, therefore returned members might have descendant keys if no depth option.
When want to filter "exact" leafs that have no descendant keys, try the following code:
// Filter leaf that depth is 3
DeepKey.keys(obj, { leaf: true }).filter(key => key.length <= 3);
Handling inextensible object
Whether specified member is present or not, DeepKey
automatically overwrite
or create member recursively, therefore exception handing is not required in
most cases.
But, there are an exception that is thrown in special case.
On object tree traversing, if intermediate inextensible object is found (null,
number, string, seald object, and so on), an error /^Inextensible object:/
be
thrown. Because such an inextensible object cannot have new extended members.
var obj = { prop1: { prop2: 1 } };
DeepKey.set(obj, [ 'prop1', 'prop2' ], 2);
// Of course, success
DeepKey.set(obj, [ 'prop1', 'prop2', 'prop3' ], 3);
// 'Inextensible object: prop1.prop2' is thrown.
// Because value 2 of prop1.prop2 is inextensible.
NOTE: Members of exsisting intermediate sealed object can be readable and writable because "seal" does not prevent to change value of its member.
var obj = { { sealed: { present: false } } };
Object.seal(obj.sealed);
DeepKey.set(obj, ['sealed', 'present'], true);
DeepKey.get(obj, ['sealed', 'present']);
// true
License
MIT license.
(C) 2016-2017 Retorillo