title: Javascript - understanding recursive inner function
body: <p>The following code prints the path of the key searched by its value inside an object:</p>
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>function findKeyPath(obj, keyAttr, keyValue) {
    let path = "";
  
    (function findKey (obj, keyAttr, keyValue, keyPath) {
  
      const prevPath = `${keyPath ? keyPath + "." : ""}`;
      if (obj[keyAttr] === keyValue) {
  
        path = `${prevPath}${keyAttr}`;
  
      } else if (typeof obj === "object" &amp;&amp; JSON.stringify(obj) === JSON.stringify(keyValue)) {
  
        path = prevPath.slice(0, -1); // remove last dot
      }
      if (typeof obj === "object" &amp;&amp; !Array.isArray(obj)) {
        for (const key in obj) {
  
          if (Array.isArray(obj[key])) {
            for (let j = 0; j &lt; obj[key].length; j++) {
  
              findKey(obj[key][j], keyAttr, keyValue, `${prevPath}${key}[${j}]`);
            }
          }
          if (obj[key] !== null &amp;&amp; typeof obj[key] === "object") {
  
            findKey(obj[key], keyAttr, keyValue, `${prevPath}${key}`);
          }
        }
      }
    }(obj, keyAttr, keyValue));
  
    return path;
  }
  
  console.log(
    findKeyPath({
      users: [
        { name: "sam", surname: "red", age: 12 },
        { name: "sam", surname: "red", age: 42 },
        { name: "sam", surname: "red", age: 16 }
      ]
    }, "age", 16)
  );</code></pre>
  </div>
  </div>
  </p>
  <p>... it prints <em>users[2].age</em>.</p>
  <p>Trying to taking out the inner function, like this:</p>
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>function findKey(obj, keyAttr, keyValue, keyPath) {
    const prevPath = `${keyPath ? keyPath + "." : ""}`;
  
    if (obj[keyAttr] === keyValue) {
  
      return `${prevPath}${keyAttr}`;
  
    } else if (typeof obj === "object" &amp;&amp; JSON.stringify(obj) === JSON.stringify(keyValue)) {
  
      return prevPath.slice(0, -1); // remove last dot
    }
    if (typeof obj === "object" &amp;&amp; !Array.isArray(obj)) {
      for (const key in obj) {
  
        if (Array.isArray(obj[key])) {
          for (let j = 0; j &lt; obj[key].length; j++) {
  
            findKey(obj[key][j], keyAttr, keyValue, `${prevPath}${key}[${j}]`);
          }
        }
        if (obj[key] !== null &amp;&amp; typeof obj[key] === "object") {
  
          findKey(obj[key], keyAttr, keyValue, `${prevPath}${key}`);
        }
      }
    }
  }
  
  console.log(
    findKey({
      users: [
        { name: "sam", surname: "red", age: 12 },
        { name: "sam", surname: "red", age: 42 },
        { name: "sam", surname: "red", age: 16 }
      ]
    }, "age", 16)
  );</code></pre>
  </div>
  </div>
  </p>
  <p>It prints <em>undefined</em>. How can I solve it?</p>
  <p><strong>UPDATE, now it works</strong>:</p>
  <pre><code>function findKey(obj, keyAttr, keyValue, keyPath) {
  
      const prevPath = `${keyPath ? keyPath + &quot;.&quot; : &quot;&quot;}`;
  
      let path = &quot;&quot;;
  
      if (obj[keyAttr] === keyValue) {
          return `${prevPath}${keyAttr}`;
      } else if (typeof obj === &quot;object&quot; &amp;&amp; JSON.stringify(obj) === JSON.stringify(keyValue)) {
          return prevPath.slice(0, -1); // remove last dot
      }
  
      if (typeof obj === &quot;object&quot; &amp;&amp; !Array.isArray(obj)) {
          for (const key in obj) {
              if (Array.isArray(obj[key])) {
                  for (let j = 0; j &lt; obj[key].length; j++) {
                      path = path.concat(findKey(obj[key][j], keyAttr, keyValue, `${prevPath}${key}[${j}]`));
                  }
              }
  
              if (obj[key] !== null &amp;&amp; typeof obj[key] === &quot;object&quot;) {
                  return path.concat(findKey(obj[key], keyAttr, keyValue, `${prevPath}${key}`));
              }
          }
      }
  
      return path;
  }
  </code></pre>