描述 JavaScript 变量
在 JavaScript 中,变量是存储位置的名称。
它可用于存储好东西、访客或者其他数据。
我们可以使用诸如“var”、“let”和“const”之类的关键字来创建变量。
存在两种类型的 JavaScript 变量:局部变量和全局变量。
局部变量在函数内部声明,或者块只能在函数或者块内访问。
相反,全局变量可以从任何函数访问。
它们可以在函数外或者使用窗口对象声明。
在此教程中,我们将解释 JavaScript 闭包是如何工作的。
通常,闭包是函数与其外部词法环境之间的唯一链接。
闭包可以被认为是支持一流功能的一种方式。
它是一个表达式,能够在其范围内引用变量。
下面是一个闭包的例子:
function sayWelcome(siteName) { let message = 'Welcome to ' + siteName; //局部变量 let welcome = function () { console.log(message); } return welcome; } let welcome1 = sayWelcome('onitroad'); welcome1(); //输出 "Welcome to onitroad"
上面提到的代码返回对函数的引用。
它有一个闭包,如匿名 function() { console.log(text); } 在另一个函数中声明。
因此,在 JavaScript 中,无论何时使用 function 关键字,都会创建一个闭包。
如果你在另一个函数中声明一个函数,那么外部函数的局部变量在从它返回后仍然可以访问。
之所以如上所示,是因为在从 sayWelcome() 返回之后调用了函数welcome1()。
被调用的代码引用了变量 message,它是 sayWelcome() 函数的局部变量:
function sayWelcome() { console.log(message); } //Output of welcome1.toString();
如果我们查看welcome1.toString() 的输出,我们将看到代码引用了变量消息。
下一个示例演示了局部变量没有被复制而是通过引用保留:
function incrementFunc() { //结束于闭包中的局部变量 let num = 5; let say = function () { console.log(num); } num++; return say; } let sayNumber = incrementFunc(); sayNumber(); //logs 6
下一个示例显示 JavaScript 闭包包含在其存在之前在外部函数中声明的任何局部变量。
请注意,变量 account 可能在匿名函数之后声明,因为 account 在同一范围内。
而且,sayWelcome()()可以直接调用sayWelcome()返回的函数引用:
function sayWelcome() { let welcome = function () { console.log(account); } //结束于闭包中的局部变量 let account = 'Welcome to oir'; return welcome; } sayWelcome()(); //输出 "Welcome to oir"
在最后一个例子中,我们演示了对 main 函数的每次调用如何创建一个单独的闭包:
function newClosure(someNumber, someReference) { //结束于闭包中的局部变量 let num = someNumber; let array = [1, 2, 3]; let ref = someReference; return function (x) { num += x; array.push(num); console.log('number: ' + num + '; array: ' + array.toString() + '; ref.someVar: ' + ref.someVar + ';'); } } obj = { someVar: 4 }; func1 = newClosure(4, obj); func2 = newClosure(5, obj); //注意这里:新闭包分配给一个新变量! func1(1); //number: 5; array: 1,2,3,5; ref.someVar: 4; func2(1); //number: 6; array: 1,2,3,6; ref.someVar: 4; obj.someVar++; func1(2); //number: 7; array: 1,2,3,5,7; ref.someVar: 5; func2(2); //number: 8; array: 1,2,3,6,8; ref.someVar: 5;
因此,可以假设每当我们在另一个函数中应用函数时,都会使用闭包。
还有另一种选择。
任何时候在函数内应用 eval() 时,都会使用闭包。
我们评估的文本可能会引用函数的局部变量。
在 eval 中,我们可以使用 eval ('var foo = …') 创建新的局部变量。
在 JavaScript 中,闭包就像保存函数存在时所有局部变量的副本。
最好认为闭包总是作为函数的入口,并且局部变量被添加到闭包中。