JavaScript函数闭包



JavaScript变量属于 本地 或者 全局 范围。

使用 闭包 可以让私有变量成为可能。


全局变量

一个函数可以访问所有定义在函数 内部 的变量,像这样:

function myFunction() {
    var a = 4;
    return a * a;
}

让我试试

但是函数也可以访问定义在函数 之外 的变量,像这样:

var a = 4;
function myFunction() {
    return a * a;
}

让我试试

在最后一个例子中,a是一个全局变量.

在网页中,全局变量属于窗口window对象.

全局变量可以被页面(和窗口)中所有脚本使用(和更改)

在第一个例子中,a是一个局部变量.

局部变量只能在定义的函数内使用。它是隐藏的在其他函数和其他脚本代码.

具有相同名称的全局变量和局部变量是不同的变量。修改一个,不修改其他.

没有关键字var创建的变量,总是全局的,即使它们是在函数中创建的.


变量的生命周期

全局变量只要你的应用程序(你的窗口/你的网页)存在,它就存在。

局部变量生命周期较短。它们在函数被调用时被创建,当函数完成时被删除。


一个计数器

假设你想使用一个变量来计数一些东西,你希望这个计数器对所有函数都可用。.

可以使用全局变量和函数来增加计数器:

var counter = 0;

function add() {
    counter += 1;
}

add();
add();
add();

// the counter is now equal to 3

让我试试

计数器只被add()函数改变。

问题是,页上的任何脚本可以改变计数器,无需调用add()。

如果我在函数中声明计数器,没有调用的时候没有人能改变它 add():

function add() {
    var counter = 0;
    counter += 1;
}

add();
add();
add();

// the counter should now be 3, but it does not work !

让我试试

它没有工作!每次我调用add()函数,计数器被设置为1

一个JavaScript内置函数可以解决这个问题.


JavaScript嵌套函数

所有函数都可以访问全局作用域.

事实上,在JavaScript中,所有函数都能访问它们外部的变量。

JavaScript支持嵌套函数. 嵌套函数可以访问它们 上面(外部) 的作用域.

在这个实例中, 内部函数 plus() 在父函数中可以访问 counter 变量:

function add() {
    var counter = 0;
    function plus() {counter += 1;}
    plus();    
    return counter;
}

让我试试

如果我们能从外部调用plus()函数,这可能已经解决了计数器的困境,

们还需要找到一种方法来执行 counter = 0 只执行一次。

我们需要闭包.


JavaScript 闭包

还记得自调用函数吗? 这个函数做什么?

var add = (function () {
    var counter = 0;
    return function () {return counter += 1;}
})();

add();
add();
add();

// the counter is now 3

让我试试

实例说明

变量add被分配了自调用函数的返回值

自调用函数只运行一次. 它将counter设置为零(0),并返回函数表达式.

这样 add 变成了一个函数. "精彩的" 部分是它可以在父作用域中访问counter。

这就是所谓的 JavaScript 闭包. 它使函数有“私有”变量成为可能.

counter受匿名函数的作用域保护, 并且只能使用add函数修改.

闭包是一个函数,即使父函数关闭后,也可以访问父作用域.