selectn

Resolves deeply-nested object properties via dot or bracket-notation for Node.js and the browser.

selectn

Resolves deeply-nested object properties via dot or bracket-notation for Node.js and the browser.

selectn('info.name.full', person)
person && person.info && person.info.name && person.info.name.full
  • Avoids if (obj && obj.a && obj.a.b && obj.a.b.c) { return obj.a.b.c; }.
  • Supports multiple levels of array nesting (i.e. group[0].section.a.seat[3]).
  • Supports dashed key access (i.e. stats.temperature-today).
  • Partial application supported.
  • Functions generated by selectn can be passed to applicative functors like Array.prototype.map and Array.prototype.filter.
  • Works where typeof fails (i.e. deeply nested properties).
  • ES5 and non-ES5 compatible.
  • CommonJS, AMD, and legacy-global compatible.
  • Provides access to global object if no object reference is given.

component

$ component install wilmoore/selectn

bower

$ bower install selectn

npm

jam

$ jam install selectn

volo

$ volo add wilmoore/selectn

global

<script src="https://raw.github.com/wilmoore/selectn/master/selectn.min.js"></script>

Given the following object:

var talk = {
  info: { name: 'Go Ahead, Make a Mess' }
};

Apply the selectn function to the path and object parameters for error-free access to deeply nested properties.

selectn('info.name', talk);
// => 'Go Ahead, Make a Mess'

Given the following object:

var talk = {
  info: { 'attendee-count': 200 }
};

Apply the selectn function to the path and object parameters for error-free access to deeply nested properties.

selectn('info.attendee-count', talk);
// => 200

Given the following list:

var talks  = [
  { info: { name: 'Go Ahead, Make a Mess' }},
  { info: { name: 'Silex Anatomy' }},
  { info: { name: 'Unit Testing in Python' }},
  { info: { name: 'Setting the Stage' }}
];

The generated function can be used as a predicate for map:

var query = selectn('info.name');
//=> [Function]

talks.map(query);
// => [ 'Go Ahead, Make a Mess', 'Silex Anatomy', 'Unit Testing in Python', 'Setting the Stage' ]

Given the following object of language strings:

var language = [
  { strings: { en: { name: 'english' } }},
  { strings: { es: { name: 'spanish' } }},
  { strings: { km: { name: 'khmer'   } }},
  { strings: { es: { name: 'spanish' } }},
];

The generated function can be used as a predicate for filter:

var spanish = selectn('strings.es');
//=> [Function]

language.filter(spanish).length;
//=> 2

You expect the following JSON data from an XMLHttpRequest:

var data = { Client: { Message: { id: d50afb80-a6be-11e2-9e96-0800200c9a66 } } };

Access the Client.Message.id property and log the result to the console (using promises):

$.ajax({...})
  .then(selectn('Client.Message.id'))
  .then(console.log.bind(console));

//=> d50afb80-a6be-11e2-9e96-0800200c9a66

NOTE: Even if you don't use this methodology in production code, it can be a handy timesaver in terms of quick debugging.

In larger, data-driven applications, there tends to be a need to do a lot of deep object access which can quickly lead to code like this:

var name;

if (contact && contact.info && contact.info.name) {
  name = contact.info.name.full || 'unknown';
}

The following is much more concise:

var name = selectn('info.name.full')(contact) || 'unknown';

In case you care about this sort of thing, we are able to do normal function application as well as partially apply when that is convenient due to currying.

  • selectn('info.name.full', contact) (normal function application)
  • selectn('info.name.full')(contact) (partial application without a partial helper like Function.prototype.bind)

Since selectn is a 2-ary function, we don't need to use an external library for currying as the algorithm is simple.

  • You can use typeof; however, typeof only "appears" to work due to the way the global scope is implied.
  • Other solutions involve eval and/or Function (eval in disguise).

MIT