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

callback function, closure and execution context

本文关键字:执行 上下文 闭包 函数 回调      更新时间:2023-09-26
function a(callback) {
    var something = 10;
    callback(something);
}
a(function(blabla) {
    console.log(blabla); // output 10
});

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

我知道"某物"是function a本地的,但是在闭包的意义上以及调用函数时创建执行上下文的事实,我希望以下内容也可以工作:

function a(callback) { 
    var something = 10; 
    callback(); 
} 
a(function() { 
    console.log(something); 
}); 

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

在第二个示例中,在回调正文中无法访问局部变量 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);
}

这在功能上与您拥有的示例相同:fooa的,bar是作为callback传入的匿名函数。

为什么调用bar()会导致打印1?该变量在foo内部局部作用域,bar对此一无所知。

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

  1. 函数体,
  2. 函数参数(适用于第一个示例(,
  3. 声明函数的作用域。

换句话说,不考虑调用范围,因此something被视为未定义。

在阅读您的问题时,在我看来,这里的主要困惑在于为什么您可以在 a 中引用something,而不是在提供给a的匿名函数中引用。

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

如果您意识到第二个代码段大致相当于:

function a(callback) { 
    var something = 10; 
    callback(); 
} 
function b() { 
    console.log(something); 
}
a(b); 

所以你可以清楚地看到这是两个完全不相关的函数,有自己的作用域。

在你的第一个例子中:-

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,并且对回调函数不可用

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

与第一个示例在函数 a 中的变量something周围创建一个闭包。如果 something 的值发生了变化,则再次调用 a 将产生不同的值。

请考虑以下传递回调函数的不同方法:

var something = "Global something";
function a(callback) {
   var something = "Local something";
   callback(something);
}
a( console.log ); // "Local something"

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

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

当您以内联方式定义函数时,它会创建自己的作用域,并引用局部变量something

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

内联函数试图console.log局部变量something,但未找到。搜索全局范围并找到"全局内容"并打印它。局部变量没有闭包。

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

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

但是x指向函数a传递的something变量,而函数又指向"局部的东西",它被打印出来。局部变量的闭包。