Skip to content

Instantly share code, notes, and snippets.

@rjz
Created May 27, 2012 17:53
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save rjz/2815273 to your computer and use it in GitHub Desktop.
Save rjz/2815273 to your computer and use it in GitHub Desktop.
Miscellaneous helpers for underscore.js
/**
* Assign a value to the delimited key in the given object. The inverse of `_.lookup`
*
* @example
*
* var myObj = {};
*
* _.assign(myObj, 'foo.bar', 'baz'); // myObj = { foo: { bar: 'baz' }}
*
* @param {Object} obj the object to assign to
* @param {String} key the key to assign to
* @param {???} value the value
*/
_.mixin({
assign: function (obj, key, value) {
var keys = key.split('.'),
cur, ptr = obj;
while ((cur = keys.shift()) && keys.length) {
if (!_.isObject(ptr[cur])) {
ptr[cur] = {};
}
ptr = ptr[cur];
}
ptr[cur] = value;
return obj;
}
});
/**
* Filter a collection based on the value of a specified key
* Requires _.lookup
*
* @example
*
* var collection = [
* { type: 'fruit', name: 'Apple' }
* { type: 'vegetable', name: 'Sprouts' }
* { type: 'fruit', name: 'Orange' }
* ];
*
* _.filterBy(collection, 'type', 'fruit');
*
* @param {Array} list the collection to filter
* @param {String} key the key to compare
* @param {???} value the required value
*/
_.mixin({
filterBy: function (list, key, value) {
return _.filter(list, function (obj) {
return _.lookup(obj, key) === value;
});
}
});
/**
* Defer a function while an action is taking place
*
* @see http://blog.rjzaworski.com/2012/02/idling-with-underscore-js/
*
* @example
*
* // `foobar` will not run until 2 seconds after the last time
* // it was called:
* var foobar = _.idle(function() {
* console.log('tic-toc');
* }, 2000);
*
* foobar();
* @param {Function} code to run eventually
* @param {Number} delay time to delay after last function call
*/
_.mixin({
idle: function(code, delay, context) {
var handle;
if (typeof(context) == 'undefined') {
context = this;
}
return function() {
if (handle) {
window.clearTimeout(handle);
}
handle = window.setTimeout(_.bind(code, context), delay);
}
}
});
/**
* Return the value corresponding to the key in the given object
*
* @example
*
* var myObj = {
* foo: { bar: 'hello, world!' }
* };
*
* _.lookup(myObj, 'foo.bar'); // "hello, world!"
*
* @param {Object} obj the object containing the key
* @param {String} key the key to look up
*/
_.mixin({
lookup: function (obj, key) {
var keys = key.split('.'),
cur = keys.shift();
if (keys.length) {
if (_.isObject(obj[cur])) {
return _.lookup(obj[cur], keys.join('.'));
} else {
return undefined;
}
} else {
return obj[cur];
}
}
});
@ikhattab
Copy link

ikhattab commented Jul 9, 2013

I tried to make something like lookup before but I used reduce instead

_.mixin({
    lookup: function (obj, key) {
        var keys = key.split('.');
        result = _.reduce(keys, function (x, y) {
            return x[y];
        }, obj);
        return result;
    }
});

@dosht
Copy link

dosht commented Jul 10, 2013

@ikhattab but this will throw an error if the keys are invalid instead of just returning undefined
try this _.lookup(myObj, 'fo2.bar');

@ikhattab
Copy link

@dosht I think this is the default behaviour if you're trying to access object with key that doesn't exist in my actual code I put it in try..catch to handle this case but I think this is another issue

@megawac
Copy link

megawac commented Aug 6, 2013

I think mixin should be written as below. Otherwise thanks!

_.mixin({
       lookup: function (obj, key){
            if (_.isString(key)) key = key.split('.');
            for (var i = 0, l = key.length; i < l; i++){
                if (_.has(obj, key[i])) obj = obj[key[i]];
                else return undefined;
            }
            return obj;
        }
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment