回调函数,闭包和执行上下文

时间:2014-06-09 11:12:45

标签: javascript

function a(callback) {
    var something = 10;

    callback(something);
}

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

好的,我没有理解这段代码的问题。

我知道“某些东西”是function a的本地,但是在封闭的意义上,以及在调用函数时创建执行上下文的事实我希望以下工作:< / p>

function a(callback) { 
    var something = 10; 

    callback(); 
} 

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

那究竟发生了什么(为什么第二个例子不起作用)?
显然,所有内容都是垃圾回收,无法在回调函数体中访问。

5 个答案:

答案 0 :(得分:4)

在第二个示例中,局部变量something在回调体中是不可访问的,不是因为它是垃圾收集,而只是因为它超出了范围。

考虑这个反例:

function a(callback) { 
    callback(); 
} 

var something = 10; 

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

此处something在定义回调正文时在范围内,因此您可以引用它。这样做会创建一个闭包。

还要考虑这个:

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

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

这在功能上与您的示例相同:fooabar是以callback传入的匿名函数。

为什么要调用bar()导致在此处打印1?该变量位于foo内的本地范围内,bar对此一无所知。

答案 1 :(得分:2)

一个函数只能引用在以下任何一个中声明的变量:

  1. 功能正文,
  2. 函数参数(适用于第一个示例),
  3. 声明函数的范围。
  4. 换句话说,调用范围不会被考虑在内,因此something被视为未定义。

答案 2 :(得分:1)

在阅读你的问题时,听起来像这里的主要混淆是为什么你可以在something内引用a,而不是在a提供的匿名函数中引用。< / p>

变量something是在函数a的上下文中定义的,而不是在匿名函数中定义的。因此,当您在匿名函数中引用something时,它实际上引用了一个隐式全局变量,在这种情况下,该变量未定义。匿名函数放在a调用的参数列表中这一事实没有任何区别。

如果您意识到第二个片段大致等同于:

,也许会更清楚
function a(callback) { 
    var something = 10; 

    callback(); 
} 

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

a(b); 

所以你可以清楚地看到这两个完全不相关的函数,它们有自己的范围。

答案 3 :(得分:1)

在你的第一个例子中: -

function a(callback) {
    var something = 10;

    callback(something);
}

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

blabla是一个变量,可以作为参数传递给a的匿名函数。因此,某些东西作为函数参数传递给回调函数,因此可以在名称blabla下运行。

但在第二个例子中: -

function a(callback) { 
    var something = 10; 

    callback(); 
} 

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

函数不知道某些东西,因为它不是全局变量/不是函数参数。

因此,当您尝试访问未定义的变量时,这是一个js错误。

因此,某些内容的范围仅限于函数a,并且回调函数无法使用

答案 4 :(得分:0)

简短回答: 由第二个示例中的回调创建的闭包将查找不存在的全局变量something

Vs以上。第一个示例在函数something中围绕变量a创建一个闭包。如果something的值发生变异,再次调用a将产生不同的值。

考虑以下不同的方式来传递回调函数:

var something = "Global something";

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

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

根据定义,console.log()将接受函数something传递的a作为其第一个参数,并将其打印到屏幕上。 关闭发生在局部变量上。

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

当您定义函数内联时,它会创建自己的范围,并引用局部变量something

函数something传递的a被删除,因为内联函数没有捕获它。 在一些更严格的语言中,它会引发错误,但JS不会。

内联函数尝试console.log找不到的局部变量something。搜索全局范围并找到“Global something”并打印它。 本地变量没有关闭。

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

内联函数创建并引用局部变量x

但是x指向由函数something传递的a变量,而该变量又指向“本地内容”,后者会被打印出来。 关闭局部变量。