JavaScript 变量属于本地或全局作用域。全局变量能够通过闭包实现局部(私有)。
我们都知道,js的作用域分全局全局作用域和局部作用域两种,js作用域环境中访问变量的权利是由内向外的,内部作用域可以获得当前作用域下的变量以及当前作用域的外层作用域下的变量,反之则不能,也就是说在外层作用域下无法获取内层作用域下的变量,同样在不同的函数作用域中也是不能相互访问彼此变量的。
var local = 1;
function foo(){
console.log(local);
}
上面三行代码中,有一个变量 local,有一个函数 foo,foo函数里面可以访问到 local 变量。这就是一个闭包。 「函数」和「函数内部能访问到的变量」的总和,就是一个闭包。
实际使用过程中,会使用函数嵌套的方式。
function bar() {
var local = 1;
function foo() {
console.log(local);
}
return foo;
}
var func = bar();
func();
上面代码中local 变量和 foo 函数就组成了一个闭包,使用函数嵌套是因为需要局部变量,所以才把 local 放在一个函数里,如果不把 local 放在一个函数里,local 就是一个全局变量了,达不到使用闭包的目的——隐藏变量(等会会讲)。简而言之,使用函数嵌套目的是让local 变量变成一个局部变量。
为什么要 return foo ?因为如果不 return,你就无法使用这个闭包。return 之后外面就可以访问到这个 foo 函数了。
下面来看一个经典例子:计数器
var add = function () {
var counter = 0;
return function foo() { return counter += 1; }
};
var func = add();
func(); //结果:counter = 1
func(); //结果:counter = 2
func(); //结果:counter = 3
上述代码中,counter 变量和 foo 函数组成了一个闭包。使用函数嵌套使得 counter 变量变成局部变量,在 add 函数外无法直接访问到(即隐藏变量)。return foo 可以暴露 foo 函数,使得通过调用 add 函数可以访问到 foo 函数。
在该例子中,在 add 函数外无法通过给 counter 变量简单赋值来修改counter,只能通过调用 add 函数来修改,从而能很好地达到计时器的效果。