闭包、作用域、上下文
闭包
学习Javascript闭包(Closure) - 阮一峰的网络日志 (ruanyifeng.com)
闭包 - JavaScript | MDN (mozilla.org)
javascript - 彻底明白作用域、执行上下文 - 个人文章 - SegmentFault 思否
function f1(){
var n=999;
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 为什么能打印出999,这个值没有被销毁吗?这段代码演示了 JavaScript 中的闭包(closure)。闭包是 JavaScript 的一个重要概念,它允许函数访问创建时的作用域链,即使该函数在其原始作用域外部被执行。
在这段代码中:
f1函数定义了一个局部变量n并赋值为999。- 在
f1函数内部,定义了另一个函数f2。f2函数通过alert显示变量n的值。f1函数通过return f2返回了函数f2的引用,而不是执行它。- 变量
result被赋值为f1函数的返回值,即f2函数的引用。- 当调用
result()时,实际上是调用了被赋值的f2函数。即使
f1函数执行完毕后,其局部变量n并没有被销毁,因为f2函数形成了对n的引用,创建了一个闭包。在闭包中,f2可以访问f1的内部状态(即变量n)。这就是为什么result()能够访问并显示n的值999的原因。这个特性不是由于
n的值没有被销毁,而是因为f2持续持有对f1作用域的引用,这个引用保持了n的值,即使f1已经执行完毕。这个持续的引用被称为闭包,它允许f2访问并操作f1的局部变量,即使f2是在f1外部被调用的。这种模式在 JavaScript 编程中非常常见,特别是在处理模块、异步回调、和各种设计模式时。
作用域、上下文
var a = 1
function out(){
var a = 2
inner()
}
function inner(){
console.log(a)
}
out() //====> 1,为什么不打印2在这段代码中,变量
a在全局作用域中被赋值为1。然后定义了out函数,在其中又局部声明并赋值为2的另一个a。接着定义了inner函数,在该函数中打印变量a的值。当调用
out()函数时,发生了以下步骤:
- 执行
out函数,创建了out函数的作用域。- 在
out函数内部声明了局部变量a并赋值为2。- 调用了
inner函数。关键点在于
inner函数。这个函数是在全局作用域中定义的,而不是在out函数内。因此,inner函数没有自己的局部变量a,它访问的是它自己作用域链中的a。由于inner函数中没有声明a,它会继续沿着作用域链向上查找,直到全局作用域中找到a的声明。由于在
inner函数中没有局部变量a的声明,它实际上访问的是全局变量a。所以,console.log(a)打印的是全局作用域中的a的值,即1,而不是out函数中的局部变量a的值2。如果你希望
inner函数打印out函数中局部作用域的a,你需要在inner函数中通过arguments.callee访问外部函数的变量(这是一种不推荐的做法,因为arguments.callee已经被标记为废弃)。或者,你可以修改inner函数,使其接收一个参数,这个参数是它应该打印的a的值:javascriptfunction inner(a) { console.log(a); } out(); // 现在会打印 2在这个修改后的版本中,当调用
out()时,inner函数接收out函数中局部作用域的a的值作为参数,并打印出来,输出结果为2。但请注意,直接将外部函数的变量传递给内部函数通常是更清晰和更推荐的做法。
