回调函数、闭包和执行上下文
callback function, closure and execution context
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);
}
这在功能上与您拥有的示例相同:foo
是a
的,bar
是作为callback
传入的匿名函数。
为什么调用bar()
会导致打印1
?该变量在foo
内部局部作用域,bar
对此一无所知。
函数只能引用在以下任一中声明的变量:
- 函数体,
- 函数参数(适用于第一个示例(,
- 声明函数的作用域。
换句话说,不考虑调用范围,因此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
变量,而函数又指向"局部的东西",它被打印出来。局部变量的闭包。
- 执行上下文和变量对象在 JavaScript 中实际上是一回事吗?
- javascript中的全局和局部变量执行上下文
- 执行上下文和Javascript中的执行上下文对象
- 函数参数的 JavaScript 执行上下文
- 逗号运算符是否会影响 Javascript 中的执行上下文
- 执行上下文和闭包
- Java 脚本 eval() 函数属于哪个对象?此外,在调用 eval() 函数时传递执行上下文
- JavaScript 范围和执行上下文
- 如何在 JavaScript 中动态地向当前执行上下文添加属性
- 任何用于 JavaScript 执行上下文可视化的现有工具
- 为什么此处未创建执行上下文
- 是否可以传递立即调用的函数表达式的执行上下文
- 如何确定 JavaScript 回调函数的执行上下文
- Node.js获取执行上下文的编程模式
- JavaScript中的执行上下文
- 获取javascript函数的绑定执行上下文
- 了解 JavaScript 提升和执行上下文
- 什么是'执行上下文'在JavaScript中
- 全局执行上下文是否可能从执行堆栈中弹出
- d3.js/CoffeeScript:访问mouseover中类和路径的执行上下文(this)