Properties of child objects using dot notation

I was temporarily stuck in what seems like a very simple JavaScript problem, but maybe I just don't have the right keywords to search!

Say we have an object

var r = { a:1, b: {b1:11, b2: 99}}; 

There are several ways to access 99:

 rbb2 r['b']['b2'] 

I want to be able to define a string

 var s = "b.b2"; 

and then press 99 using

 rs or r[s] //(which of course won't work) 

One way is to write a function for it that breaks the string into a point and, possibly, gets the property recursively / iteratively. But is there an easier / more efficient way? Anything useful in any of the jQuery APIs here?

+78
javascript jquery
Nov 08 2018-11-11T00:
source share
13 answers

Here's a naive function that I wrote some time ago, but it works for the basic properties of an object:

 function getDescendantProp(obj, desc) { var arr = desc.split("."); while(arr.length && (obj = obj[arr.shift()])); return obj; } console.log(getDescendantProp(r, "b.b2")); //-> 99 

Although there are answers that extend this to β€œallow” access to the index of the array, this is not entirely necessary, as you can simply specify numeric indices using dot notation using this method:

 getDescendantProp({ a: [ 1, 2, 3 ] }, 'a.2'); //-> 3 
+92
Nov 08 '11 at
source share

split and reduce when passing an object like initalValue

 var r = { a:1, b: {b1:11, b2: 99}}; var s = "b.b2"; var value = s.split('.').reduce(function(a, b) { return a[b]; }, r); console.log(value); 

Update (thanks to the comment posted by TeChn4K)

With ES6 syntax it's even shorter

 var r = { a:1, b: {b1:11, b2: 99}}; var s = "b.b2"; var value = s.split('.').reduce((a, b) => a[b], r); console.log(value); 
+63
Oct 28 '15 at 17:29
source share

If it is possible in your script that you can put the entire array variable in a string, you can use the eval() function.

 var r = { a:1, b: {b1:11, b2: 99}}; var s = "rbb2"; alert(eval(s)); // 99 

I feel people swinging in horror

+17
Nov 08 2018-11-11T00:
source share

You can use the lodash get () and set () methods .

Getting

 var object = { 'a': [{ 'b': { 'c': 3 } }] }; _.get(object, 'a[0].b.c'); // β†’ 3 

Customization

 var object = { 'a': [{ 'b': { 'c': 3 } }] }; _.set(object, 'a[0].b.c', 4); console.log(object.a[0].bc); // β†’ 4 
+16
Jul 04 '15 at 18:22
source share

Extension of @JohnB's answer, I added the setter value. Check plunkr for

http://plnkr.co/edit/lo0thC?p=preview

enter image description here

 function getSetDescendantProp(obj, desc, value) { var arr = desc ? desc.split(".") : []; while (arr.length && obj) { var comp = arr.shift(); var match = new RegExp("(.+)\\[([0-9]*)\\]").exec(comp); // handle arrays if ((match !== null) && (match.length == 3)) { var arrayData = { arrName: match[1], arrIndex: match[2] }; if (obj[arrayData.arrName] !== undefined) { if (typeof value !== 'undefined' && arr.length === 0) { obj[arrayData.arrName][arrayData.arrIndex] = value; } obj = obj[arrayData.arrName][arrayData.arrIndex]; } else { obj = undefined; } continue; } // handle regular things if (typeof value !== 'undefined') { if (obj[comp] === undefined) { obj[comp] = {}; } if (arr.length === 0) { obj[comp] = value; } } obj = obj[comp]; } return obj; } 
+12
Nov 21 '13 at 15:50
source share

This is the easiest way:

 var accessProperties = function(object, string){ var explodedString = string.split('.'); for (i = 0, l = explodedString.length; i<l; i++){ object = object[explodedString[i]]; } return object; } var r = { a:1, b: {b1:11, b2: 99}}; var s = "b.b2"; var o = accessProperties(r, s); alert(o);//99 
+8
Nov 08 '11 at 14:40
source share

you can also do

 var s = "['b'].b2"; var num = eval('r'+s); 
+5
Nov 08 '11 at
source share

I do not know the supported jQuery API function, but I have this function:

  var ret = data; // Your object var childexpr = "b.b2"; // Your expression if (childexpr != '') { var childs = childexpr.split('.'); var i; for (i = 0; i < childs.length && ret != undefined; i++) { ret = ret[childs[i]]; } } return ret; 
+2
Nov 08 '11 at 2:37
source share

I expanded Andy E's answer so that it can also process arrays:

 function getDescendantProp(obj, desc) { var arr = desc.split("."); //while (arr.length && (obj = obj[arr.shift()])); while (arr.length && obj) { var comp = arr.shift(); var match = new RegExp("(.+)\\[([0-9]*)\\]").exec(comp); if ((match !== null) && (match.length == 3)) { var arrayData = { arrName: match[1], arrIndex: match[2] }; if (obj[arrayData.arrName] != undefined) { obj = obj[arrayData.arrName][arrayData.arrIndex]; } else { obj = undefined; } } else { obj = obj[comp] } } return obj; } 

There are probably more efficient ways to run Regex, but they are compact.

Now you can do things like:

 var model = { "m1": { "Id": "22345", "People": [ { "Name": "John", "Numbers": ["07263", "17236", "1223"] }, { "Name": "Jenny", "Numbers": ["2", "3", "6"] }, { "Name": "Bob", "Numbers": ["12", "3333", "4444"] } ] } } // Should give you "6" var x = getDescendantProp(model, "m1.People[1].Numbers[2]"); 
+2
Sep 27 '13 at 10:52 on
source share

Here is the Andy E code extension that overwrites arrays and returns all values:

 function GetDescendantProps(target, pathString) { var arr = pathString.split("."); while(arr.length && (target = target[arr.shift()])){ if (arr.length && target.length && target.forEach) { // handle arrays var remainder = arr.join('.'); var results = []; for (var i = 0; i < target.length; i++){ var x = this.GetDescendantProps(target[i], remainder); if (x) results = results.concat(x); } return results; } } return (target) ? [target] : undefined; //single result, wrap in array for consistency } 

So, given this target :

 var t = {a: {b: [ {'c':'x'}, {'not me':'y'}, {'c':'z'} ] } }; 

We get:

 GetDescendantProps(t, "abc") === ["x", "z"]; // true 
+2
Aug 28 '14 at 11:01
source share

Performance tests for Andy E's, Jason More and my own solution are available at http://jsperf.com/propertyaccessor . Please feel free to run the tests using your own browser to add to the collected data.

The forecast is clear, the Andy E solution is the fastest to date!

For everyone who is interested, here is the code for my solution to the original question.

 function propertyAccessor(object, keys, array) { /* Retrieve an object property with a dot notation string. @param {Object} object Object to access. @param {String} keys Property to access using 0 or more dots for notation. @param {Object} [array] Optional array of non-dot notation strings to use instead of keys. @return {*} */ array = array || keys.split('.') if (array.length > 1) { // recurse by calling self return propertyAccessor(object[array.shift()], null, array) } else { return object[array] } } 
+2
Aug 12 '15 at 1:07
source share

Short answer: No, there is no built-in .access function as you want it. As you mentioned correctly, you will need to define your own function that breaks the string and loops / checks in parts.

Of course, what you can always do (even if it is considered bad practice) is to use eval() .

how

 var s = 'b.b2'; eval('r.' + s); // 99 
0
Nov 08 '11 at
source share

Here is a little better than @andy , where obj (context) is optional , it returns to window if not specified ..

 function getDescendantProp(desc, obj) { obj = obj || window; var arr = desc.split("."); while (arr.length && (obj = obj[arr.shift()])); return obj; }; 
0
Sep 30 '13 at 14:21
source share



All Articles