简体   繁体   中英

callback function, closure and execution context

function a(callback) {
    var something = 10;

    callback(something);
}

a(function(blabla) {
    console.log(blabla); // output 10
});

Ok i dont have problem understanding this code.

I know that "something" is local to function a and but in the sense of closures and fact that execution context is created when function is called i expected following to work also:

function a(callback) { 
    var something = 10; 

    callback(); 
} 

a(function() { 
    console.log(something); 
}); 

So what happened exactly (why second example don't work)?
Obviously everything is garbage collected and not accessible in body of callback function.

In the second example, the local variable something is not accessible in the body of your callback not because it's garbage collected, but simply because it is out of scope.

Consider this counter-example:

function a(callback) { 
    callback(); 
} 

var something = 10; 

a(function() { 
    console.log(something); 
});

Here something is in scope at the time the body of the callback is defined so you can reference it. Doing so creates a closure.

Also consider this one:

function foo() {
    var xyz = 1;
    bar();
}

function bar() {
    console.log(xyz);
}

This is functionally the same example as you have: foo is a and bar is the anonymous function passed in as callback .

Why should calling bar() result in printing 1 here? That variable is locally scoped inside foo , and bar knows nothing about it.

A function can only reference variables that are declared in either:

  1. the function body,
  2. the function arguments (applies in 1st example),
  3. the scope where the function was declared.

In other words, the calling scope is not taken into account and so something is considered undefined.

In reading your question, it sounds to me like the primary confusion here is in why you can reference something inside a , but not inside the anonymous function provided to a .

The variable something is defined within the context of the function a , not within the anonymous function. So when you reference something inside the anonymous function, it actually references an implicit global variable, which in this case is not defined. The fact that the anonymous function is placed within the parameter list of a call to a makes no difference.

Perhaps it would be more clear if you realize that the second snippet is roughly equivalent to:

function a(callback) { 
    var something = 10; 

    callback(); 
} 

function b() { 
    console.log(something); 
}

a(b); 

So you can see clearly these are two completely unrelated functions, with their own scopes.

In your first example:-

function a(callback) {
    var something = 10;

    callback(something);
}

a(function(blabla) {
    console.log(blabla); // output 10
});

blabla is a variable which is available to the anonymous function passed as parameter to a. So something is passed to callback function as function parameter and is hence available to function under name blabla.

But in second example:-

function a(callback) { 
    var something = 10; 

    callback(); 
} 

a(function() { 
    console.log(something); 
}); 

something is unknown to the function as its not a global variable/ is not a function parameter.

So this is a js error as you are trying to access an undefined variable.

So scope of something is limited to the function a and is not available to the callback function

Short answer: The closure created by the callback in the second example, will look for the global variable something which does not exist.

Vs. the first example creates a closure around the variable something within function a . If the value of something is mutated, calling a again will produce a different value.

Consider the following different ways to pass callback functions:

var something = "Global something";

function a(callback) {
   var something = "Local something";
   callback(something);
}

a( console.log ); // "Local something"

As defined, console.log() will accept the something passed by function a as its first argument and prints it out to the screen. Closure happens on the local variable.

a( function() {console.log(something)} ); //"Global something"

When you define a function inline it creates its own scope, and references a local variable something .

The something passed by function a gets dropped as the inline function did not catch it. In some stricter languages it will throw an error, but JS does not.

The inline function tries to console.log the local variable something , which is not found. Searches global scope and finds "Global something" and prints it. No closure on the local variable.

a( function(x) {console.log(x)} ); //"Local something"

The inline function creates and references local variable x .

But x points to the something variable passed by function a , which in turn which points to "Local something", which gets printed. Closure on the local variable.

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