3

If I define an inner function inside a function, the inner function has access to the outer function's variables. If I want this inner function to be reusable and define it outside the outer function, the inner function now loses access to the outer function variables. How do I make this new reusable inner function have access to outside function variables, without passing those variables in as parameters?

        function a () {

        var x = [[1,2,3], [1,2,3], [1,2,3]];

        var keys = Object.keys(x[0]);

        for (var i = 0; i < x.length; i++) {
            angular.forEach(keys, loop);
        }

        }

        function loop (key) {
            console.log(key, i);//i is undefined here
        }
        a();

Specifically, is there some way without 1) assigning variables to this, 2) without passing in variables as parameters, and 3) without creating global variables?

Edit: It seems there is no way to do this. But if I try another approach, to have the reusable function return a new function, I also do not have access to the inner scope. Why is this, and is there some way to make this work?

        function a () {

        var x = [[1,2,3], [1,2,3], [1,2,3]];

        var keys = Object.keys(x[0]);
        var myloop = loop();

        for (var i = 0; i < x.length; i++) {
            angular.forEach(keys, myloop);
        }

        }

        function loop (key) {
            return function(key) {
                 console.log(key, i);//i is undefined here
            };
        }
        a();
dz210
  • 748
  • 1
  • 8
  • 20
  • 1
    Use global variables may be, though it's not recommended. – Pritam Banerjee Feb 23 '16 at 16:49
  • Any way besides using global variables? I think there must be some way with closures, but I cannot get it to work. – dz210 Feb 23 '16 at 16:50
  • Making a reusable function depend on variables from outside of its scope seems like a really bad idea to me. What's the issue with just passing `i` into the function? – Joe Clay Feb 23 '16 at 16:53
  • The issue is that you will need to create an anonymous function to do this. angular.forEach(keys, function(key) { loop(key, i)}) – dz210 Feb 23 '16 at 16:55
  • What is this function supposed to accomplish? So `keys` contains the keys (or index values) of the first array in `x`. Then you're iterating over the length of `a` (the function, which has a length of zero, so the loop will never run), and if the loop were to execute somehow, you loop over the keys again. Can you clarify? – Adeel Zafar Soomro Feb 23 '16 at 17:15
  • @AdeelZafarSoomro Sorry it should be x.length, my mistake. – dz210 Feb 23 '16 at 17:17

5 Answers5

2

In the following example, loop returns a function that closes over the value of i.

function a () {
    var x = [[1,2,3], [1,2,3], [1,2,3]];

    var keys = Object.keys(x[0]);

    for (var i = 0; i < keys.length; i++) {
        keys.forEach(loop(i));
    }
}

function loop (i) {
    return function (key) {
        console.log(key, i);  // i is now defined
    }
}

a();

Output:

0 0
1 0
2 0
0 1
1 1
2 1
0 2
1 2
2 2
Adeel Zafar Soomro
  • 1,492
  • 9
  • 15
1

How do I make this new reusable inner function have access to outside function variables, without passing those variables in as parameters?

You can't. JavaScript has lexical scope, not dynamic scope.

See also: What is lexical scope?

Community
  • 1
  • 1
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
1

I also want to make another option known which I just discovered. If you use .bind, you can curry the function with i, and the other variables will be passed in after the curried parameters.

 ....
 angular.forEach(keys, loop.bind(null, i));
 ...

 function loop(i, key) {
 ...
 }
dz210
  • 748
  • 1
  • 8
  • 20
0

Inner functions are treated locally by the outer function. Therefore, you can access the variables belonging to the outer function from the inner function. But, once you have the inner function as a separate function outside the outer function, then you no longer have access to the private data variables of the outer function.

If this seems complicated, here is an example:

function A
{
  //variables
  function B
  {
   can use variables of A
  }
}

But,

    function A
    {
      //variables
    }
    function B
    {
     //cannot access variables of A
    }
Adarsha
  • 21
  • 1
  • 7
0

In JS (and many other languages), there is a visibility context. Possible contexts are e.g. "global" or function or block. These contexts are hierarchical, inner can read outer. Outer can never read inner (encapsulation principle) unless inner declares variable as global.