本文介绍下,关于

  • js 闭包
  • GC
  • 私有变量

之间的关系
也是为了面试准备的文章,毕竟当面试官问你闭包是什么的时候只回答闭包的概念未免显的单薄,能扯出上边这些方面知识至少不会冷场。

关于闭包

闭包包含自由(未绑定到特定对象)变量,这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义(局部变量)。 —— 百度百科

这个fn就是一个闭包,fn内部可以访问外部的变量。

  1. let a = 1
  2. let b = 2
  3. a = 3
  4. function fn() {
  5. return a + b
  6. }

这种语言特性并不是在所有语言中都存在。
比如在java中,lambda中引用的变量必须是final类型的变量,即使不需要声明这个变量是final类型的,但这个引用的变量必须是既成事实上的final变量,否则会导致无法通过编译。
image.png

GC —— 垃圾回收

看这段代码

  1. var outerFn = function () {
  2. let a = { b: 1 };
  3. return () => {
  4. return a;
  5. };
  6. };
  7. let fn = outerFn();
  8. let res = fn();
  9. res.c = 2;
  10. console.log(JSON.stringify(res));
  11. outerFn = null;
  12. setTimeout(() => {
  13. console.log(fn());
  14. }, 1000);

在第8行执行完这个函数后整个的outerFn就执行完了,如果正常的话里边用到的变量都会被GC清空,但我们通过操作res引用改变内部对象a发现居然还可以作用在函数的内部对象a上!也就是说在函数执行完后变量依旧留在内存中没有被回收。

私有变量

上边代码可能有迷惑性,毕竟是一个复合类型的变量;如果是一个基本类型的则可以构成私有变量,在外界无法修改,毕竟是一个函数返回的值吗,已经做了一次拷贝,如果是复合类型的话则返回的是引用能修改。

  1. var outerFn = function () {
  2. let a = 1;
  3. return {
  4. get: () => {
  5. return a;
  6. },
  7. set: (num) => {
  8. a = num;
  9. },
  10. };
  11. };
  12. let fn = outerFn();
  13. let res = fn.get();
  14. res = 2;
  15. console.log(res);
  16. fn.set(3)
  17. console.log(fn.get());

next
weakmap、强引用弱引用与闭包
https://stackoverflow.com/questions/111102/how-do-javascript-closures-work