简体   繁体   中英

Not understanding scope in Javascript

I don't quite understand this bit of code.

$('div').click((function () { 
    var number = 0;
    return function () {
        alert(++number);
    };
})());

My understanding is:

  • An anonymous function is defined and assigned to the click handler.

  • When I click on div, this function is invoked.

What the function does is:

  • Define a variable number = 0

  • Return ++number

So why does the number in alert increment every time I click? Shouldn't number be reset to 0 every time I click?

Here you've got a self-invoking function , which returns a function. Watch out for the brackets at the end:

(function () { 
    var number = 0;
    return function () {
        alert(++number);
    };
})()

So the callback of the click handler is only the returned inner function :

function () {
    alert(++number);
};

This inner function has access to the variable number , which is in the scope of the outer function.

So your code can also be written as follows:

function outerFunction() {
    var number = 0;
    return function () {
        alert(++number);
    };
};

var innerFunction = outerFunction();

$('div').click(innerFunction);

If we used (ugly) names for the anonymous functions, your code could be rewritten as:

$('div').click((function makeIncrementer() {
    var number = 0;
    return function incrementAndAlert() {
        alert(++number);
    };
})());

More verbose code retaining similar semantics would be:

var makeIncrementer = function() {
    var number = 0;
    return function() { alert(++number); };
};

var incrementAndAlert = makeIncrementer(); // function() { alert(++number); }

$('div').click(incrementAndAlert);

makeIncrementer is a function that, when called, defines a number variable in its scope, and returns a function - note that makeIncrementer doesn't increment, nor alert the number variable, instead it returns another function that does just that.

Now incrementAndAlert is bound to this returned function

function() { alert(++number); }

that captures makeIncrementer 's number variable, which enables it to keep number 's state between incrementAndAlert calls triggered by $('div') clicks.

This is not an "answer", but hopefully it will show a different way of looking at the problem.


First off, note that JavaScript functions are just objects and are thus just values that can be bound to variables. As such,

$('div').click((function () { 
    var number = 0;
    return function () {
        alert(++number);
    };
})());

can be, with a simple expression substitution, rewritten as

var f = function () { 
    var number = 0;
    return function () {
        alert(++number);
    };
};
// $('div').click((f)()); and when removing extra parenthesis ->
$('div').click(f());

Then, after one more simple expression substitution

var g = f()
$('div').click(g);

it should be clear that the (outer) function, f , is invoked first and it is the resulting (inner function) value, g , that is used as the handler.

Aside from introducing variables, the above substitutions are semantically equivalent to the original code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM