开发者

I don't understand this example of a closure

Crockford had this example to keep myArray from being in the global scope:

var myName = (function() {
    var myArray = ['zero','one','two','three','four'];
    return function(X) {
        return myArray[X];
    }
}()); // This function is invoked immediately

result = myName(3); // Now invoke it "for real"

Q: I don't get why it isn't

var myName = (function(X) {

Q: When I call myName(3), isn't "var myArray=" executed a 2nd time? Suppose it's not executed a 2nd time because JavaScript knows开发者_如何学Python that it's already been defined... What about a loop or some other logic between the var stmt and the return function stmt? Wouldn't it be executed every time?

Q: Can you name the subfunction and call it instead of calling myName?


okay, let's break this down...

var myName = (function(){
    ...
}());

that piece sets myName to whatever that anonymous function returns, so if it were:

var myName = (function(){ return 42; }());

myName would equal 42. If that doesn't make sense, this is the same thing:

function someFunction(){ return 42; }
var myName = someFunction();

So in your example, myName is set to function(X){ return myArray[X] }. So myName is a function. When you call it, the only code that is run is return myArray[x]. myArray is kept in what is called a closure, it is only exposed to the myName function and the anonymous one surrounding it.

I wrote an article on closures years back that may help you: http://www.htmlgoodies.com/primers/jsp/article.php/3606701/Javascript-Basics-Part-9.htm (scroll down to the "Closures" header).


OK here it goes .. answer to Q1 . it is not myName = (function(x) because the part inside the brackets returns a function which takes X . i.e. myname is not assigned to (function(){}) but to the return value of it .

Q2. No when u calll myName 2nd time it already points to the inner function hence the outer function is not invoked at all .(this is the sepciality of closures where the value stays alive in inner function even if outer functions are completed.)

Q3. Well nopes we can name the inner function but the name will be valid only inside the outer function and since outer function has completed the name would be useless.


The outer function doesn't have to have an argument X, because it's only purpose is to return another function (which then is parametrized). Thus no argument is needed here.

Thus the only effect is to bind the function(X)... thing to the variable myName. Therefore no other constructs like loops or so does make sense here.


Q1+2: Note the () right of the comment "This function is invoked immediately". The outer function defined is not stored in myName, but immediatly called. Itself then returns an anonymous function which has no name and requires a single parameter (X). This function beeing returned is stored in myName.

To grasp closure you should start thinking about functions just as another value of a variable which can be stored and returned jsut as any other value.

Q3: myName is the subfunction.


Okay answer in turn:

First, why it's var myName = (function() { and not var myName = (function(x) {

In this case because the x value isn't required to create the function you are returning. The data structure of the array contained in the returned function is hard coded and so you don't need additional information to construct it. Much in the same way that

function a() { 
  return 1 + 2;
}

Doesn't have any arguments, because it's values are hardcoded. This is an example of functions as data or first class functions

Question two: is var myArray executed every time.

The short of it is no. myArray has been assigned to at this point so it has a value that the system has already calculated. In this case it's a function. The myArray potion has been set and so there is no cause to keep executing it. If the outer function didn't return a new function then yes it would need to get called again and again but that would defeat the purpose of this abstraction.

Question three: can you call the inner function.

No, it's out of scope. The entire point of this example is that you have defined a function generator.


Answer to first question: no, the first "line" is returning a function so when you call "myName" you are actually executing the returned function

function(X) {
        return myArray[X];
}

Answer to second question

no, such a function can still refer to the array "myArray"... in fact the purpose of this closure is to make myArray available in the global scope


In words:

myName is the result of an immediately executed anonymous function. It returns a function reference (to an anonymous function). That function has one parameter: X. After execution of the topmost anonymous function, myName is a reference to the inner anonymous function.

Now the inner anonymous function has access to myArray via a closure (myArray and the returned anonymous function both live within the scope of the topmost anonymous function). So if you execute myName, you actually execute the inner anonymous function, which can access myArray.

The topmost anonymous function is executed immediately and once (it returns a reference to the inner function). So myArray is declared within that execution context, and only once.


Since the definition of the myName object (function) ends in '()', its function is called immediately, returning a new function which has the myArray variable statically bound to it. myName is then accessible globally but myArray is not as it is within a function closure. When you reference myName() it has exclusive access to the bound array.


This approach ensures that myArray is only allocated once, when the outer function 'is invoked immediately'. After it is invoked, myArray isn't in the global scope, but is still available to the anonymous inner function.

The approach you proposed would work, but would require that the array be allocated each time the function was called. (Or be allocated outside the function, in the global scope.)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜