var foo = (function开发者_如何学Python(){
var x = 0;
return function(){return x++;};
})()
Why the var x = 0 expression only runs once is my biggest misunderstanding about this.
Your code:
var foo = (function(){
var x = 0;
return function(){return x++;};
})()
is equivalent to this code:
function f(){
var x = 0;
return function(){return x++;};
}
var foo = f();
It's easy to see, when you break it up like this, that the function f()
is only called once. It defines x
, and then returns a new function that is defined inside the local scope of f
. This new function is often called an "anonymous function" (meaning that it has no name) or a "closure". In truth, all functions in javascript are "closures" -- whether or not they are named. The term "closure" simply means that the function retains access to the variables that were defined in the parent function's scope -- even after the parent function has exited.
So now, foo
contains the new function (the closure) that was returned from f
. You can call foo()
as many times as you like -- and each time you do, x
will be returned and post-incremented. Since x
exists in the closure's parent scope, its value will persist across multiple calls to the closure.
What's more... no other code now has access to x
once f()
has exited -- this basically means that x
is now the "private data" of the closure. Pretty neat huh?
The variable foo
is being assigned to the result of the self-executing function, which goes as follows:
Declares a variable named x
initialized to 0
.
Returns a function that, when invoked, will increment the value of x
.
So at this point, foo
references a function.
The way you would invoke this is:
foo();
The first time this is invoked, the value returned will be 0
, then 1
, 2
...
Well, wait a minute..., shouldn't it be 1
, 2
, 3
...?
You are on the right track, but the reason why in this case this isn't true is because of the difference between pre-increment and post-increment. (++var
vs var++
). The difference is that the result of a pre-increment is the variable's value after increment, while the result of a post-increment is the variable's value before increment.
This example illustrates the concept of closures, which essentially means that inner functions have access to the variables defined in their surrounding functions.
Let's break it down... First we define an anonymous function:
(function() { ... })
We then immediately execute it:
(function() { ... })()
The result of this execution is another function:
function(){return x++;}
And the x=0 is captured by the closure when we created the above function. We then assign this resulting function to foo:
var foo = function(){return x++;}
With the value of x captured by the closure. Whenever foo is executed, x is incremented.
The anonymous function gets invoked immediately by the ()
that follows it (passing in no parameters). That function when executed is returning another function, which has it's own x
variable that gets incremented when run.
So foo()
is going to be 0
the first run, 1
the second, etc, since that x
it was created with continues to increment.
Actually in this case x
is a local variable within the block/closure assigned to the foo
object. One that gets incremented when you call foo()
.
Check it out in action - http://jsfiddle.net/3X283/
This is what is called a closure theere are two functions defined - the inner one (which is the closure) and the outer one which creates and returns the closure.
Your code calls the outer function immediately and assigns the result (the closure) to foo
.
Note the code inside the closure does not include the statement var x = 0;
thus when you call foo()
it only executes the code inside the closure (return x++;
)
The x
referred to in here is the one instantiated in the call. What makes closures interesting is that this x is different between invocations of the outer function - consider the example below. foo and bar will increment independantly of one another because they reference different x
s
function makeClosure(){
var x = 0;
return function(){return x++;};
}
var foo = makeClosure();
var bar = makeClosure();
foo(); //returns 0
foo(); //returns 1
bar(); //returns 0
foo(); //returns 2
精彩评论