闭包可以让这些变量的值始终保持在内存中,那为什么这样输出后还是原来的值

function f1(){
    var n =9;
    nAdd=function(){
        n=n+1;
    }
    function f2(){
       console.log(n);
    }
    return f2;
}
 var result=f1();
 result(); //9
 nAdd();
 result();// 10

 var consult=f1();
 consult();//9

如图代码所示,正在学习闭包,阮老师提到闭包作用之一就是可以让这些变量的值始终保存在内存中,

1.那为什么consult()这里打印出来的不是10,而是9呢?n值不是被保存下来了吗?

2.还有就是“f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中” 这句话又是什么意思呢?f2为什么被赋给了一个全局变量?这个变量是谁?

回复
阅读 3.4k
3 个回答

1.每次运行f1,函数体都会重新执行,所以在第二次运行f1后,nAdd函数体中的n已经变成了新的n,值为9

2.全局变量是resultconsult。这句话的f2f1指的是运行上下文,具体到这个问题可以理解为变量nf2

闭包讲清楚不是很容易,我尽量讲得清楚些

1.那为什么consult()这里打印出来的不是10,而是9呢?n值不是被保存下来了吗?
这个问题可以简化下,实际就是下面这个问题:
var result=f1(); // 内存里保存了一个 n
var consult=f1(); // 内存里也保存了一个 n 

问题是,但是这两个 n 是同一个么?

如果是同一个,那就是题主的意思;
不是同一个,就是阮老师的意思;

实际上不是同一个,js权威指南上是这么说的

clipboard.png

我的理解就是,这个 n 是函数调用的时候才添加到作用域链的,那么两次调用函数赋值给变量,当然声明了两次,添加了两次,而且在不同的作用域链中,如果是同一个 n 在同一个作用域,不就是重复声明了么?你把 var 换成 let 会报错的,为什么说在不同的作用域链中呢?当你声明了 consult 之后,consult的作用域链中全局对象里有 result,result的作用域链中全局对象里有 consult 嘛?明显没有啊,所以两个 n 在不同的作用域链中,当然不是同一个;或者再粗浅理解下,你调用一个函数两次赋值给不同变量,难道函数内的变量都是为两个变量共享,用的是同一个嘛?当然不是啊,,,

2.还有就是“f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中” f2为什么被赋给了一个全局变量?这个变量是谁?
var result=f1(); // f1() 函数执行到 return f2,就把 f2 赋值给了 result,result 是全局变量
var consult=f1(); // f1() 函数执行到 return f2,就把 f2 赋值给了 consult,consult 是全局变量
2.还有就是“f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中” 这句话又是什么意思呢?
var result=f1();//result=f2 不完全等价,但是可以用来参考

因为把 f2 赋值给 result,实际上就是在 result 上保存了对 f2的引用,而 f2 里又保存了对 n 的引用,而 f2 和 n 都存在于 f1 的局部环境里,所以导致了 n,f2,f1 都不会被垃圾回收,也就是说 f2,f1,n 都保存在内存中;(因为 js 的垃圾回收机制存在引用计数的规则,当这个值的引用次数变成 0 时,这个值才会被垃圾回收,释放内存,引用次数不为 0 ,就继续保存在内存中,不会被垃圾回收)
(实际上我觉得 f1 已经不在内存中了,不过这个不影响闭包的理解)

新手上路,请多包涵

因为:

var result = f1();   生成了一个小明

var consult = f1();   生成了一个李红

他们是两个独立的东西。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏