# selectn [![Build Status](https://travis-ci.org/wilmoore/selectn.png?branch=master)](https://travis-ci.org/wilmoore/selectn) [![Build Status](https://david-dm.org/wilmoore/selectn.png)](https://david-dm.org/wilmoore/selectn) [![NPM version](https://badge.fury.io/js/selectn.png)](http://badge.fury.io/js/selectn) [![frozen](http://hughsk.github.io/stability-badges/dist/frozen.svg)](http://nodejs.org/api/documentation.html#documentation_stability_index) Resolves deeply-nested object properties via dot or bracket-notation for [Node.js][] and the browser. #### So you can do: selectn('info.name.full', person) #### instead of: person && person.info && person.info.name && person.info.name.full ## Features - 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][map] and [Array.prototype.filter][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. ## Non-Features - No `eval` and [friends][Function]. ## Installation [component](http://component.io/wilmoore/selectn) $ component install wilmoore/selectn [bower](http://sindresorhus.com/bower-components/) $ bower install selectn [npm](https://npmjs.org/package/selectn) [![NPM](https://nodei.co/npm/selectn.png?downloads=true)](https://nodei.co/npm/selectn/) [jam](http://jamjs.org/packages/#/details/selectn) $ jam install selectn [volo](http://volojs.org) $ volo add wilmoore/selectn [global][] ## Examples - [Nested property access](#nested-property-access) - [Dashed keys](#dashed-keys) - [Iterator](#iterator) - [Predicate](#predicate) - [Callback](#callback) ### Nested property access 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' ### Dashed keys 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 ### Iterator 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' ] ### Predicate 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 ### Callback 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. ## Rationale 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'; ## Neckbeard Info 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. ## Alternatives - 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`][note] in disguise). ## Inspiration - [to-function][] - [reach][] - [dref][] ## License MIT [to-function]: https://github.com/component/to-function [reach]: https://github.com/spumko/hoek#reachobj-chain [dref]: https://github.com/crcn/dref.js [Function]: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function [eval]: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/eval [note]: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Member_Operators#Note_on_eval [typeof]: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/typeof [promises]: http://promises-aplus.github.io/promises-spec/ [map]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map [filter]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter [global]: http://yuiblog.com/blog/2006/06/01/global-domination/ [Node.js]: http://nodejs.org