Javascript 在闭包中,为什么主变量没有在每次调用时重置?
我正试图对闭包有一个坚实的理解,我正在与闭包的机制作斗争。我看过w3schools()和MDN()以及其他一些地方。我理解闭包是什么,以及如何使它工作,但我不理解为什么在第一次调用外部函数之后,后续调用似乎直接进入内部函数 以下是我的代码-一个简单、有效的闭包:Javascript 在闭包中,为什么主变量没有在每次调用时重置?,javascript,closures,Javascript,Closures,我正试图对闭包有一个坚实的理解,我正在与闭包的机制作斗争。我看过w3schools()和MDN()以及其他一些地方。我理解闭包是什么,以及如何使它工作,但我不理解为什么在第一次调用外部函数之后,后续调用似乎直接进入内部函数 以下是我的代码-一个简单、有效的闭包: var add = (function () { var a = 0; alert('hi'); function addInner(){ a += 1; return a;
var add = (function () {
var a = 0;
alert('hi');
function addInner(){
a += 1;
return a;
}
return addInner;
})();
function getAdd() {
document.getElementById("test").innerHTML = add();
}
我有两个问题可能都有相同的答案:为什么每次调用add()
时a
都没有重置?为什么除了第一次,警报不会弹出?
我在一个按钮上附加了getAdd()
,它工作得很好,但第一次出现警报时不会弹出。为什么会这样
编辑:我还发现这个问题的第一个答案()非常有用
var add = (function () {
var a = 0;
alert('hi');
function addInner(){
a += 1;
return a;
}
return addInner;
})(); <-- This
因为现在你会认为
add.a
会使a
可用,因为它被写为this.a
,但是既然addInner
被返回,那么它就不可用。add
是对addInner
的引用,而不是匿名的“outer”函数,因为“outer”是函数返回addInner
。然后,调用该匿名函数一次,即最后一组()
,并将结果函数及其自己的私有“a”存储在add
中
假设外部函数是一个名为constructAdder
的命名函数,您调用了
var add = constructAdder();
var add2 = constructAdder();
这基本上就是您所做的,但是使用匿名函数,如果这能让它更清楚的话。由于闭包的魔力,您有一个外部函数,它构造了一个可以计数的内部函数。您应该关注
(function(){
// impl
})()
街区。
它被称为立即调用的函数表达式或IIFE
因此,当代码执行到第1行时,它首先计算右侧,IIFE返回一个闭包,然后将闭包分配给变量add。同时,在IIFE中调用了一个警报。了解iLife可以帮助你解决问题。在我看来,关键是,在第一次执行下面的代码之后
var add = (function () {
var a = 0;
alert('hi');
function addInner(){
a += 1;
return a;
}
return addInner;
})();
(小心!上面的代码中没有add()
,因为iLife将立即被调用,返回addInner
完成变量add
的初始化)
功能add
已更改为:
add = function addInner() {
a += 1;
return a;
}
当然,alert()只执行一次,因为add
在开始时已更改
为什么每次调用add()时都不重置
为什么除了第一次,警报不会弹出
这就是你问题的答案
变量
a
没有销毁,因为函数add
仍然有一个引用,这是关于闭包的这些问题的答案是相同的。这相当简单。本声明:
var val = (function() {
return 42
}())
将val
设置为42。不是一个函数。这称为或立即调用的函数表达式。我们正在声明一个函数并立即调用它。我们从不保存该函数。我们只需使用它一次即可获得它返回的值:
val // 42
与之相比:
var val = function() {
return 42
}
在本例中,我们将val
设置为一个函数,该函数在调用时返回42
val() // 42
val() // 42
我们可能会对iIFE感到非常疯狂:
var val = (function() {
return (function() {
return (function() {
return 42
}())
}())
}())
该混乱返回的值仍然是42
val // 42
所有这些函数声明一次,使用一次,然后丢弃。但IIFE的能力远不止这些:
var add = (function() {
var counter = 0
return function() {
return counter++
}
}())
我们现在使用IIFE来创建一个私有变量<代码>计数器
无法在IIFE范围外访问。很安全。但是内部函数可以访问和修改它。这是一个完全封装的、有状态的函数
add() // 0
add() // 1
counter // Uncaught ReferenceError: counter is not defined
这就是您的代码所做的:
var add = (function () {
var a = 0;
alert('hi');
function addInner(){
a += 1;
return a;
}
return addInner;
})();
它封装了a
变量,因此不能在IIFE范围之外访问它。但是,addInner
功能确实可以访问a
,并且可以随意修改它
alert()
只被调用一次,因为iLife只被调用一次,然后被丢弃。请注意,函数本身是唯一被丢弃的东西。由于addInner
维护对IIFE创建的作用域(闭包)的引用,因此该作用域不会被垃圾收集
事实上,这是思考IIFE的一种有用的方式:
var val = function() {}
创建函数并
val()
创建闭包(函数体在其中运行的上下文)。当我们不关心函数时,使用IIFEs,我们只需要它创建的闭包
希望这有帮助。玩得开心 谢谢!我没有意识到外部功能被丢弃了。现在有道理了。我会继续练习的。
val()