0

I do not understand how calling this function works

function setup(x) {
    var i = 0;
    return function () {
        console.log(i);
        return x[i++];

    };
}

var next = setup(['a', 'b', 'c']);

console.log(next());//a
console.log(next());//b
console.log(next());//c

how is i not reset to 0 with each call?

1252748
  • 14,597
  • 32
  • 109
  • 229
  • possible duplicate of [How do JavaScript closures work?](http://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – Mike Samuel Mar 05 '13 at 08:15
  • @MikeSamuel I've looked through that post before and it's a little different in that i'm just curious about this particular iterator, not broadly "how do closures work". – 1252748 Mar 05 '13 at 08:20
  • the first answer to that question will also answer "how is `i` not reset to 0 with each call?" – Mike Samuel Mar 05 '13 at 08:33

2 Answers2

1

In your code:

> function setup(x) {
>     var i = 0;

When setup is called, a new execution context is created with local variables x and i. When execution begins, x is assigned a value of the passed array and i is set to zero.

>     return function () {
>         console.log(i);
>         return x[i++];
>     };

This anonymous function is returned. It has a closure to the outer execution object that is placed on its scope chain (so is the global execution object).

So it has a closure to both i and x, whose values can now only be changed by the function.

> }
>
> var next = setup(['a', 'b', 'c']);

The returned function is assigned to next, so it's no longer anonymous.

> 
> console.log(next());//a

When this line executes, next returns x[0], which is "a", and increments i to 1.

> console.log(next());//b

When this line executes, next returns x[1], which is "b", and increments i to 2.

> console.log(next());//c

When this line executes, next returns x[2], which is "c", and increments i to 3.

RobG
  • 142,382
  • 31
  • 172
  • 209
  • "_So it has a closure to both i and x, whose values can now only be changed by the function._" Okayy. But what prevents `i` from being reset each time? If I put something like `console.log('after i')` on the line after `var i = 0`, and then do the three `console.log(next());`s I only see the printout of `after i` one time — [JSBIN](http://jsbin.com/emagit/1/edit). I just don't understand how that named function `setup()` can be called without its executing anything outside the anonymous function on the 2nd and 3rd calls. Sorry to be daft.. :/ – 1252748 Mar 05 '13 at 16:37
  • `i` is not reset because `setup` is only called once. After that, `next` is called, which assigns a new value (`i++`) each time. – RobG Mar 05 '13 at 20:48
  • Okay...making more sense. Thank you. so [this fiddle example](http://jsbin.com/uguvig/1/edit) knows that `setup` is a function because even though `next()` only points to the returned function, because when it was initially created, it had access to the parent function `setup()`? It would have access to many layers of "parent" functions? I hope this question is clear. Please let me know if I need to edit it.. – 1252748 Mar 05 '13 at 20:57
  • Yes. When a function is called, its scope chain is created that has each outer execution context on it. Functions can be nested very deep (e.g. recursion). Identifier resolution is like property resolution, only it's along the scope chain rather than inheritance (`[[Prototype]]`) chain. – RobG Mar 05 '13 at 22:12
0

i is not reset, because it was set outside of the function that is assigned to next. In fact in the line directly above it.

nfechner
  • 17,295
  • 7
  • 45
  • 64
  • I don't get it. it looks like it's set on the first line of the function that is assigned to `next`, _viz_. `reset()` – 1252748 Mar 05 '13 at 08:22
  • No, the line `var next = setup(['a', 'b', 'c']);` **calls** the setup function, which returns a **different** anonymous function. `i` is set outside of that function, so it doesn't get reset. – nfechner Mar 05 '13 at 08:27