4
\$\begingroup\$

I wrote the following code as a way of plucking data from a n-depth JavaScript object. It works a charm and even appends the parents of the the found item.

I was just wondering if you guys had any ideas on making it better.

//#region function recursiveFind
function recursiveFind(data, key, childKey, match, result) {
 ///<summary>Returns JS obj and its parents based on a data set, key and match.</summary>
 ///<param name="data" type="Object" optional="false">the data object you want to find within</param>
 ///<param name="key" type="String" optional="false">the key for the data you want to match against eg. 'id' will look for data.id</param>
 ///<param name="childKey" type="String" optional="false">the data object you want to find within</param>
 ///<param name="match" type="Any" optional="false">the value you wish to search for</param>
 ///<returns type="Object">returns the found result</returns>
 var parents = [];
 var depth = 0;
 var recurse = function (data, key, childKey, match, result) {
 // Build Parents
 depth++;
 // Check this Object
 if (data[key] === match) {
 result = data;
 }
 else if (depth === 1) {
 parents.push(data);
 }
 // If not found check children
 if (result === undefined) {
 if (data[childKey]) {
 $.each(data[childKey], function (k, v) {
 if (v[key] === match) {
 result = v;
 return false;
 } else {
 result = recurse(v, key, childKey, match, result);
 if (result) {
 parents.push(v);
 return false;
 }
 }
 });
 }
 }
 // Set parents object into the result
 if (result) {
 result.parents = $.extend([], parents);
 }
 // Clean up parents object
 depth--;
 if (depth === 0) {
 parents.length = 0;
 }
 return result;
 };
 return recurse(data, key, childKey, match, result);
}
//#endregion
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked May 21, 2013 at 15:29
\$\endgroup\$
3
  • \$\begingroup\$ You you add an example of use? \$\endgroup\$ Commented Oct 11, 2013 at 20:13
  • \$\begingroup\$ Are you sure ` parents.length = 0;` works? \$\endgroup\$ Commented Dec 16, 2013 at 19:52
  • \$\begingroup\$ @tomdemuyt yep, it is the preferred way of reseting an array in JavaScript stackoverflow.com/questions/1232040/… \$\endgroup\$ Commented Dec 17, 2013 at 10:58

1 Answer 1

6
\$\begingroup\$

Overal

I think the code looks too busy just to find a key/value match in an object tree-structure, it took a while to figure out which part(s) bothered me.

Doing it twice

You are doing the matching twice, once with (data[key] === match) and once with (v[key] === match), it would be cleaner to leave the second check to recursion.

Function in a function

I am assuming you use a function in a function to keep track of depth and parents, which isn't worth it. You can do this in a single function with an optional parameter.

Naming

  • match -> matchValue because match sounds like a boolean to me
  • childKey - childrenKey because the key really points to an array
  • result.parents -> avoid this, what if the object already has a property called parents ?

Counter proposal

If you think about it, result can be considered the parent of key, so I would build a function that returns all parents in an array, if you wish you can then have recursiveFind call that.

function findParents( data, key, matchValue, childrenKey, parents )
{
 var i , children , childrenCount;
 /* Prevent the need for an inner function by re-passing parents */
 parents = parents || [];
 parents.push( data )
 /* Return immediately if we find a match */
 if( data[key] === matchValue )
 return parents.reverse(); 
 /* Are there children to inspect ? */
 if( !data[childrenKey] || !data[childrenKey].length )
 return false;
 children = data[childrenKey];
 childrenCount = children.length;
 /* See if any children have it ? */
 for( i = 0 ; i < childrenCount ; i++ )
 {
 if( parents = findParents( children[i] , key , matchValue , childrenKey , parents.slice() ) )
 return parents;
 }
 /* Fail.. */
 return false;
}

Then recursiveFind becomes

function recursiveFind(data, key, childrenKey, match )
{
 var parents = findParents( data , key, match ),
 result = parents.shift()
 result.parents = parents;
 return result;
}
answered Dec 21, 2013 at 18:31
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.