1. 变量作用域要理解闭包,首先要先理解javascript变量的作用域变量的作用域只有两种:全局变量 + 局部变量全局变量:任何地方都可以访问(函数内部、外部)局部变量:只能在变量所在函数及函数的子
1. 变量作用域
要理解闭包,首先要先理解javascript变量的作用域变量的作用域只有两种:全局变量 + 局部变量
全局变量:任何地方都可以访问(函数内部、外部)局部变量:只能在变量所在函数及函数的子函数中访问:fa-exclamation-circle:注意:变量声明如果不使用var关键字,那么他就是一个全局变量,即使是在函数内部定义
1.1 计算器困境:
希望计算器的值counter能够被修改,但是不希望被任意更改(只能+1)全局变量实现:
var counter = 0; function add(){ ++counter; } add(); //1 add(); //2 add(); //3 问题:counter的值可以被任意更改。
局部变量实现:
function add(){ var counter = 0; ++counter; } add(); //1 add(); //1 add(); //1 问题:counter的值不能按照设想来正确输出。
javascript的闭包就可以解决该问题。
2. javascript内嵌函数
在javascript中,所有的函数均可以访问它们上层的作用域
function add(){ var counter = 0; function plus(){ ++counter; }}
上面代码中,plus函数在add函数内部,这使得add内部的所有局部变量都是对plus可见的,但是反过来却不行。这就是javascript语言特有的【链式作用域】结构(chain scope)
如果我们能够在外部访问plus函数,那么这个【计算机困境】就能够解决了所以,只要将plus函数作为add函数的返回值,就可以访问plus函数了,也就可以通过plus函数,在add函数外部访问add函数局部变量了
================以上所说就是闭包。
3. javascript中的闭包
当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。闭包就是将函数内部和函数外部连接起来的一座桥梁
3.1 闭包的用途:
- 可以读取函数内部的变量
- 可以让函数内部变量的值始终保存在内存中
计算机困境可以更改为以下两种方式:
1:(建议)var add = (function(){ var counter = 0; return function plus(){return ++counter;}})();add(); //1add(); //2add(); //32:function add(){ var counter = 0; return function plus(){return ++counter;} } var f1 = add(); f1(); //1 f1(); //2 f1(); //3
以上证明:局部变量counter一直在内存中, 并没有在函数执行完后自动清除。why??????because:--add是plus的父函数,而plus被赋给了一个全局变量,导致plus始终在内存中,而plus函数依赖于add函数,所以add也一直在内存中,不会再结束后被GC回收。
3.2 getter/setter
function add(){ var counter = 0; getCounter = function(){ reutrn counter; }}
注意add中的getCounter变量,因为没有使用var来声明,所以它是一个全局变量,可以当做java中的getter来使用:fa-hand-o-down:
public class add{ private int counter = 0; public int getCounter(){ return counter; }}
3.3 闭包应该注意的问题
- 由于闭包使得函数中的变量,都被保存在内存中,内存消耗很大,所以不能滥用闭包。否则会造成网页性能问题,甚至会内存泄漏。解决方案:退出函数之前,将不使用的局部变量全部消除(变量的值为null即可)。
- 如果把函数当做Object使用,不要随便通过setter/闭包改变函数内部的变量值。