一、什么是闭包
闭包指能够访问另一个函数作用域的变量的函数,一般是定义在外层函数中的内层函数。
例:
function outer(){
//创建了局部变量
var name="张三";
//内部函数(闭包)
function inner(){
//使用父函数声明的变量
console.log(name);
}
inner();
}
outer();
解析1:
outer() 创建了一个局部变量 name 和一个名为 inner() 的函数。
inner() 是定义在 outer() 里的内部函数,仅在该函数体内可用。
inner() 内没有自己的局部变量,可以访问到外部函数的变量,所以 inner() 可以使用父函数 outer() 中声明的变量 name 。但是,如果有同名变量 name 在 inner() 中被定义,会使用 inner() 中定义的 name 。
解析2:
词法作用域中使用的域,是变量在代码中声明的位置所决定的。嵌套的函数可以访问在其外部声明的变量。
闭包是由函数以及创建该函数的词法环境组合而成。这个环境包含了这个闭包创建时所能访问的所有局部变量。
在 inner
函数中获取 name,首先在 inner
函数的作用域中查找 name,未找到,进而在 outer
函数的作用域中查找,发现在outer
作用域中存在 name,因此获取 name 值并打印。
即变量都存在指定的作用域中,如果在当前作用中找不到想要的变量,通过作用域链向父作用域中继续查找,直到找到第一个同名的变量为止(或找不到,抛出 ReferenceError 错误)。这是 js 中作用域链的概念,即子作用域可以根据作用域链访问父作用域中的变量。
JavaScript中的函数运行在它们被 定义 的作用域里,而不是它们被执行的作用域里。
二、为什么使用闭包
使用闭包主要是为了:
- 封装数据
- 暂存数据
局部变量无法共享和长久的保存,而全局变量可能造成变量污染,所以我们希望有一种机制既可以长久的保存变量又不会造成全局污染。
三、缺点
- 占用更多内存
- 不容易被释放
四、何时使用
变量既想反复使用,又想避免全局污染。
五、如何使用
- 定义外层函数,封装被保护的局部变量。
- 定义内层函数,执行对外部函数变量的操作。
- 外层函数返回内层函数的对象,并且外层函数被调用,结果保存在一个全局的变量中。
参考链接:
通俗易懂地解释JS中的闭包
MDN:闭包