先导知识:
- JavaScript中作用域有两大类:全局作用域和局部作用域
- JavaScript中变量有:全局变量和局部变量
- JavaScript中没有命名空间的概念
- JavaScript中函数内可以嵌套定义函数
- 在函数局部作用域中可以访问全局变量,反之不行。
Question:我们需要在全局作用域中访问局部作用域中的局部变量,为了解决这个问题,有了闭包的概念。
一、定义
《javascript高级程序设计》:闭包是指有权限访问一个函数作用域中局部变量的函数。
二、展示
假设我们需要一个计数器变量count,用来计数。这时我们可以这样去写。
/**
* 直接定义全局变量用来计数
*/
var count = 0;
但是这样一来任何,任何地方都可以访问这个变量,而且会有被重新赋值的危险。
所以我们可以这样去写:
/**
* 将计数变量放到函数内部
*/
function count(){
var count = 0;
return count += 1;
}
count(); // 1
count(); // 1
但是这样就会一直输出1,以为每次调用都会重新定义一个count并初始化这个变量。
那再改造一下:
/**
* 改造版的计数器实现
*/
function counter(){
let count = 0;
function plus(){
count += 1;
}
plus();
return count;
}
console.log(counter()); // 1
console.log(counter()); // 1
我们发现内嵌函数可以访问外层函数的变量,这样我们只要保证:
- 外层函数无法访问
- 内部变量只初始化一次
- 外层函数暴露一个接口,该接口可以操作其内部变量
/**
* 计数器的闭包实现
* 通过立即执行的匿名函数 + 内部函数
*/
let counter2 = (function(){
let count = 0;
return function(){ return count += 1; }
})();
console.log(counter2()); // 1
console.log(counter2()); // 2
console.log(counter2()); // 3
这样立即执行函数只执行一次,同时又可以返回一个函数用来操作外层匿名函数的局部变量,这样就形成了一个 闭包。
闭包是一种私有变量保护机制,在函数执行时形成私有作用域,保护里面的私有变量不受外接环境的影响。
直观的说就是形成一个不销毁的栈环境。
缺点
因为无法销毁,所以可能造成内存泄露!!