deep-key

0.9.9 • Public • Published

deep-key

Build Status Coverage Status Dependency Status NPM MIT

"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 member
  • value : value of member that is pointed by deepkey
  • 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

Package Sidebar

Install

npm i deep-key

Weekly Downloads

1

Version

0.9.9

License

MIT

Last publish

Collaborators

  • retorillo