描述 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 中,闭包就像保存函数存在时所有局部变量的副本。
最好认为闭包总是作为函数的入口,并且局部变量被添加到闭包中。
