Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/443.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在闭包中,为什么主变量没有在每次调用时重置?_Javascript_Closures - Fatal编程技术网

Javascript 在闭包中,为什么主变量没有在每次调用时重置?

Javascript 在闭包中,为什么主变量没有在每次调用时重置?,javascript,closures,Javascript,Closures,我正试图对闭包有一个坚实的理解,我正在与闭包的机制作斗争。我看过w3schools()和MDN()以及其他一些地方。我理解闭包是什么,以及如何使它工作,但我不理解为什么在第一次调用外部函数之后,后续调用似乎直接进入内部函数 以下是我的代码-一个简单、有效的闭包: var add = (function () { var a = 0; alert('hi'); function addInner(){ a += 1; return a;

我正试图对闭包有一个坚实的理解,我正在与闭包的机制作斗争。我看过w3schools()和MDN()以及其他一些地方。我理解闭包是什么,以及如何使它工作,但我不理解为什么在第一次调用外部函数之后,后续调用似乎直接进入内部函数

以下是我的代码-一个简单、有效的闭包:

  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()