闭包的定义
何为闭包?引用MDN里的定义:
函数与对其状态即词法环境(lexical environment)的引用共同构成闭包(closure)。也就是说,闭包可以让你从内部函数访问外部函数作用域。在JavaScript,函数在每次创建时生成闭包。
简单的讲,闭包就是能够读取其他函数内部变量的函数。
在讲闭包之前,我们需要知道以下的一些概念:
- 作用域
作用域
作用域无非分为两种:全局的和局部的。
拿全局变量来说,就是不管在函数内部还是外部,都能够读取该变量;局部变量则是在函数作用范围内才能读取。
举个例子来说:
var a = 2;
function fn1() {
console.log(a); // 2
}
fn1();
上述例子中,a变量声明在全局,所以在fn1函数中能够读取它的值,如果反过来会怎样?
function fn1() {
var a = 2;
}
fn1();
console.log(a); // Uncaught ReferenceError: a is not defined
很显然,在函数外部是不能够读取到函数内部定义的变量的。
这里需要注意的是,如果在函数内部不使用var定义,实际上定义的是一个全局变量。
function fn1() {
a = 2;
}
fn1();
console.log(a); // 2
这里我们可以简单的总结一下:函数内部变量也是逐级向下传递的,内部的可以访问父级的变量。其实,这也不难理解,就像我们之前讲到的原型链一样,也是层级关系。
那么,如何从外部读取局部变量呢?
在我们实际的应用中,主要有以下两种方式:
1. 函数作为返回值
2. 函数作为参数
函数作为返回值
当然是在函数里面再定义一个函数了,看下面这个例子:
function fn1() {
var a = 2; // a是fn1内的局部变量
function fn2() {
var b = a + 3;
return b;
}
return fn2();
}
fn1(); // 5
我们在fn1函数的内部定义了一个fn2函数,fn2中可以获取到变量a的值,同时,在fn2外面,我们也能获取到变量b的值。这里的fn2其实就是一个闭包。
函数作为参数
var a = 2;
function fn1(x) {
return x;
}
function fn2() {
return a + 3;
}
fn1(fn2()); // 5
闭包的用途
最主要的是以下两点:
1. 读取函数内部的变量
2. 变量在调用后不会被清除,所以,闭包不能滥用,容易造成内存泄漏。当然,定义的变量也是手动清除的。