Created
July 30, 2012 17:06
-
-
Save furf/3208381 to your computer and use it in GitHub Desktop.
underscore.js mixin for plucking nested properties
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
_.mixin({ | |
// Get/set the value of a nested property | |
deep: function (obj, key, value) { | |
var keys = key.replace(/\[(["']?)([^\1]+?)\1?\]/g, '.$2').replace(/^\./, '').split('.'), | |
root, | |
i = 0, | |
n = keys.length; | |
// Set deep value | |
if (arguments.length > 2) { | |
root = obj; | |
n--; | |
while (i < n) { | |
key = keys[i++]; | |
obj = obj[key] = _.isObject(obj[key]) ? obj[key] : {}; | |
} | |
obj[keys[i]] = value; | |
value = root; | |
// Get deep value | |
} else { | |
while ((obj = obj[keys[i++]]) != null && i < n) {}; | |
value = i < n ? void 0 : obj; | |
} | |
return value; | |
} | |
}); | |
// Usage: | |
// | |
// var obj = { | |
// a: { | |
// b: { | |
// c: { | |
// d: ['e', 'f', 'g'] | |
// } | |
// } | |
// } | |
// }; | |
// | |
// Get deep value | |
// _.deep(obj, 'a.b.c.d[2]'); // 'g' | |
// | |
// Set deep value | |
// _.deep(obj, 'a.b.c.d[2]', 'george'); | |
// | |
// _.deep(obj, 'a.b.c.d[2]'); // 'george' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
_.mixin({ | |
pluckDeep: function (obj, key) { | |
return _.map(obj, function (value) { return _.deep(value, key); }); | |
} | |
}); | |
// Usage: | |
// | |
// var arr = [{ | |
// deeply: { | |
// nested: 'foo' | |
// } | |
// }, { | |
// deeply: { | |
// nested: 'bar' | |
// } | |
// }]; | |
// | |
// _.pluckDeep(arr, 'deeply.nested'); // ['foo', 'bar'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
_.mixin({ | |
// Return a copy of an object containing all but the blacklisted properties. | |
unpick: function (obj) { | |
obj || (obj = {}); | |
return _.pick(obj, _.difference(_.keys(obj), _.flatten(Array.prototype.slice.call(arguments, 1)))); | |
} | |
}); |
Is this in any git repo? It is nice functionality and could just fit in a bower package..
Time saved, cheers Furf.
Fantastic! Very elegant. Thanks.
see also https://github.com/chaijs/pathval and Ember's getPath / setPath
for deepPick see also https://gist.github.com/onexdrk/0b0b84fe6f0c8f0a895b
What if the array index was blank. How could you do something like this?
var obj = {
a: {
b: {
c: {
d: ['e', 'f', 'g']
}
}
}
};
_.deep(obj, 'a.b.c.d[]'); // "['e', 'f', 'g']"
Worth noting, you can use native Underscore (>= v1.8.0
) to achieve this by using _.property
along with _.compose
. Example below:
var nested = {
colors: {
red: '#ff0000',
green: '#008000',
blue: '#0000FF'
}
}
var getGreen = _.compose(_.property('green'), _.property('colors'));
console.log({normal: nested.colors.green, underscore: getGreen(nested)})
//==> Object {normal: "#008000", underscore: "#008000"}
Definitely not the most palatable way to do it...
You could put this concept into a mixin easily though:
_.mixin({
/* usage: _.nestedProperty('colors', 'green') */
nestedProperty: function(/*args*/) {
var props = _.toArray(arguments);
// Reverse b/c compose operates right to left, but usage is left to right
// Map result is [_.property(argN), .... _.property(arg2), _.property(arg1)]
return _.compose.apply(null, props.reverse().map(_.property) );
});
It seems to have issues when you go too deep like
//Define X
let x = { test1 : { test2: { test3: { test4 : 'Hello World' } } } };
_.deep(x, 'test1.test2.test3.test4') // This will work but now lets make it to where test 3 doesn't exist
x = { test1 : { test2: { } };
_.deep(x, 'test1.test2.test3.test4') // This will throw an error on lookup which i can understand since this also has the ability to set but i thought i would bring this up
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I wrote these functions before I found this but I will remember these for next time!