1
\$\begingroup\$

I have complex objects containing nested objects. I need to check if a key exists anywhere in the nested object. I wrote this code as a makeshift solution. Is there any other way to search for the key?

function checkKey(obj, key) {
    if(key in obj){
        return obj[key];
    }
    else{
        for (k in obj){
            t = obj[k]
            if(typeof t === "object" && !Array.isArray(t) && t !== null){
                return checkKey(t, key);    
            }
        }
    }
    return false
}

Test object:

obj = {
    "l1":"test333",
    "some":{
        "l2":"test2",
        "l22":"test3",
        "other":{
            "l3":["yellow"]
        }
    }
}

Search: checkKey(obj, "l3"); returns ["yellow"]

\$\endgroup\$
4
  • \$\begingroup\$ the code is mostly OK, with one major problem - it'll fail if the value of the key found is "falsey" \$\endgroup\$
    – Alnitak
    Dec 4, 2015 at 9:07
  • \$\begingroup\$ I would initialize var t; somewhere (and k also). also this code does not work with this case : jsfiddle.net/Hacketo/38jn92ab \$\endgroup\$
    – Hacketo
    Dec 4, 2015 at 9:13
  • \$\begingroup\$ Your code should check that checkKey returns a value before returning it. Here, it'll only ever search the first sub-object it finds at each level. \$\endgroup\$
    – jcaron
    Dec 4, 2015 at 9:59
  • \$\begingroup\$ @Hacketo, debugged. \$\endgroup\$
    – jerrymouse
    Dec 4, 2015 at 10:21

1 Answer 1

2
\$\begingroup\$

Your code has a couple of problems:

Semantic

You are using the construction key in obj, without checking if key is an actual property of obj. If obj is not an Object, but instead something resembling a class:

var PolarBear = function() {
  this.cuddly = true;
}

PolarBear.prototype.growl = function() {
  //nothing
}

Passing an instance of PolarBear to your function will return a function reference whenever you check if "growl" is a key. You could change this behaviour by checking if obj.isOwnProperty( key ) is true, or checking if obj is an Object.

Logic errors

Early return

If a key is an Array, and that array does not contain your key, your code will return anyway, even though you have not checked every key yet.

An example would be key "c" in the following Object. It is there, but your code would return false instead of 2, because the Object under key "a" does not contain a key "c".

{
  "a" : {
    "b" : 1
  }
  "c" : 2
}

Not exact key

Your code does not check if the key requested is the actual key we get. Some keys are transformed to an actual key. For example:

{
  "" : 1,
  "null" : 2,
  "false" : 3
}

Obviously, "" in obj would return true, but so would [] in obj, or null in obj, or false in obj, even though strictly speaking there is no key with that name. You could instead do Object.keys( obj ).indexOf( key ) > -1.

Not returning key of Object under Array

You are silently ignoring Arrays. I suspect you do this because you do not want to return keys in Arrays, but this also means that if you have an Object inside your Array, you'll silently ignore this. For example, the key "c" in the following Object will be ignored, and thus false will be returned

{
  "a" : [
    { "b" : 1 },
    { "c" : 2 }
  ]
}
\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.