搜索

首页  >  问答  >  正文

关于 javascript 闭包的问题?

为什么变量 n 不会被重置?

function f1(){
    var n=999;
    nAdd=function(){n+=1}
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result=f1();
  result(); // 999
  nAdd();
  result(); // 1000
  

说明变量 n 是个全局变量,是不是在 f2 中变量 n 被提升为了全局变量?

高洛峰高洛峰2827 天前990

全部回复(9)我来回复

  • 给我你的怀抱

    给我你的怀抱2017-05-18 10:52:47

    因为js会给每个函数调用创建一个栈,函数内的函数也可以访问这个栈。

    首先你能调用nAdd,是因为你没加var,等于是在函数调用时定义了一个全局作用域下的nAdd,你加上var再这么写会报错。

    你的var result=f1();调用了函数f1,也就创建了一个栈,保存了n=999,并返回了f2。之后你再怎么调用result(),其实都是在调用同一个f2,而这个f2引用的外部栈,自然还是第一次调用f1时候创建的那个。同样的nAdd虽然作用在全局,但访问的也是同一个栈内的数据。

    所以,并不是你说的因为nAdd是全局变量,所以n被提升成全局变量,而是nAdd所指向的函数和你返回的那个闭包根本是在访问同一份数据。

    你可以尝试着改写成

    function f1(){
        var n=999;
        nAdd=function(){n+=1}
        function f2(){
          alert(n);
        }
        return f2;
      }
    
      f1()(); // 调用f1,创建了一个栈,栈内n=999,创建了一个匿名函数,返回了一个闭包。
      nAdd(); // 调用了那个匿名函数
      f1()(); // 又调用f1,又创建了一个栈,栈内n=999,创建了另一个匿名函数,返回了另一个闭包。

    回复
    0
  • 我想大声告诉你

    我想大声告诉你2017-05-18 10:52:47

    在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。
    为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
    这段代码中另一个值得注意的地方,就是"nAdd=function(){n+=1}"这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。
    http://www.ruanyifeng.com/blo...

    回复
    0
  • ringa_lee

    ringa_lee2017-05-18 10:52:47

    不是 n 被提升为全局变量了,这就是闭包。。。。
    nAdd是全局变量。
    nAddresult中涉及的n 都是 var n = 999那个n,而没有全局的n

    http://zonxin.github.io/post/...

    回复
    0
  • 仅有的幸福

    仅有的幸福2017-05-18 10:52:47

    var nAdd = ... 你再试试你就知道为什么了

    没有var声明 就会被提升为全局变量

    变量n不是全局变量 只是这样写让这个n的内存始终得不到释放

    回复
    0
  • 给我你的怀抱

    给我你的怀抱2017-05-18 10:52:47

    f2函数中对f1函数内的局部变量n持久引用,f2返回后,n不会被释放,而nAdd作为一个全局函数,当然可以操作n

    回复
    0
  • ringa_lee

    ringa_lee2017-05-18 10:52:47

    n还是局部变量,因为一直都是在函数f1中在进行对局部变量n的操作。而nAdd()是一个全局下的函数,在他执行的时候,会将他所属作用域中的n进行了加1

    回复
    0
  • 阿神

    阿神2017-05-18 10:52:47

    • var result=f1(); 调用时,返回了一个内部函数f2,并且引用了外部函数的变量n,由于垃圾回收机制,f1被执行完毕的时候,。n一直没有被回收,result()执行第二次的时候,n变成了1000

    • nAdd 全局变量,没有添加var,所以是全局作用域

    • n 是局部变量

    回复
    0
  • 黄舟

    黄舟2017-05-18 10:52:47

    1. var result=f1():f1函数返回了f2函数
      把返回的f2函数赋值给result全局变量,(f2的作用域链保存到result全局变量中)

    2. result():调用result(),这就形成闭包:有权访问另外一个函数作用域中的变量
      因为在f2中的作用域引用了f1中的n这个局部变量,当f1执行完毕后,垃圾回收机制发现n变量还在被result中引用所以垃圾回收机制不会把n回收释放。
      以至于n一直保存在result作用域链中。result的作用域链正常能访问f1中的局部变量n,形成闭包。

    3. nAdd():nAdd没有写var所以nAdd是全局变量,在调用nAdd()和result()是一样的都会形成闭包,匿名函数function(){n+=1}的作用域链中有n这个局部变量,所以当nAdd=funtion(){n+=1}时,这个匿名函数的作用域链保存到了全局变量nAdd形成闭包,调用nAdd()作用域链中找到f1局部变量n=999,n+1=1000。

    4. result():result()就输出1000

    只是本人理解,如有错误请拍砖告知

    回复
    0
  • PHP中文网

    PHP中文网2017-05-18 10:52:47

    n不是一个全局变量,这是一个闭包。为什么n会改变,因为你的那个nAdd前面没有写var默认全局的,但是你的function是在闭包里面定义的,作用域什么的都是里面的。

    回复
    0
  • 取消回复