In the JavaScript functions chapter you‘ve learn that in JavaScript a variable‘s scope can be global or local. Since ES6 you can also create block-scoped variables using the
let
keyword.在JavaScript函数一章中,您已经了解到,在JavaScript中,变量的作用域可以是全局或局部的。
A global variable can be accessed and manipulated anywhere in the program, whereas a local variable can only be accessed and manipulated by the function they are declared in.
全局变量可以在程序中的任何位置访问和操作,而局部变量只能由声明它们的函数访问和操作。
However, there are certain situations when you want a variable to be available throughout the script, but you don‘t want just any part of your code to be able to change its value accidentally.
然而,在某些情况下,您希望变量在整个脚本中都可用,但是您不希望代码的任何部分都能意外更改其值。
Let‘s see what happens if you try to achieve this using the global variable:
让我们看看如果您尝试使用全局变量来实现此目标,将会发生什么:
// Global variable
var counter = 0;
// A function dedicated to manipulate the ‘counter‘ variable
// 专门用于操纵‘counter‘变量的函数
function makeCounter() {
return counter += 1;
}
// Calling the function
makeCounter();
console.log(counter); // Prints: 1
makeCounter();
console.log(counter); // Prints: 2
// Trying to manipulate the ‘counter‘ variable from outside
// 试图从外部操纵‘counter‘变量
counter = 10;
console.log(counter); // Prints: 10
As you can see in the above example, the value of the
counter
variable can be changed from anywhere in the program, without calling themakeCounter()
function如您在上面的示例中看到的那样,可以在程序中的任何位置更改计数器变量的值,而无需调用makeCounter()函数
Now, let‘s try to achieve the same thing with the local variable and see what happens
现在,让我们尝试使用局部变量来实现相同的目的,然后看看会发生什么
function makeCounter() {
// Local variable
var counter = 0;
// Manipulating the ‘counter‘ variable
return counter += 1;
}
// Calling the function
console.log(makeCounter()); // Prints: 1
console.log(makeCounter()); // Prints: 1
In this case the
counter
variable cannot be manipulated from outside, since it is local tomakeCounter()
function, but its value will also not increase after subsequent function call, because every time we call the function it reset thecounter
variable value, which you can clearly see in the above example (line no-11). The JavaScript closure can solve our problem.在这种情况下,无法从外部操作计数器变量,因为它是makeCounter()函数的本地变量,但在后续函数调用后其值也不会增加,因为每次调用该函数都会重置计数器变量值,您可以可以在上面的示例(第11行)中清楚地看到。JavaScript闭包可以解决我们的问题。
A closure is basically an inner function that has access to the parent function‘s scope, even after the parent function has finished executing. This is accomplished by creating a function inside another function. Let‘s take a look at the following example to see how it works:
闭包基本上是一个内部函数,即使父函数执行完毕,它也可以访问父函数的作用域。这是通过在另一个函数内部创建一个函数来实现的。让我们看下面的示例,看看它是如何工作的:
function makeCounter() {
var counter = 0;
// Nested function
function make() {
counter += 1;
return counter;
}
return make;
}
/* Execute the makeCounter() function and store the
returned value in the myCounter variable */
// 执行makeCounter()函数并存储myCounter变量中返回的值
var myCounter = makeCounter();
console.log(myCounter()); // Prints: 1
console.log(myCounter()); // Prints: 2
As you can see in the above example, the inner function
make()
is returned from the outer functionmakeCounter()
. So the value of themyCounter
is the innermake()
function (line no-14), and callingmyCounter
effectively callsmake()
. In JavaScript functions can assigned to variables, passed as arguments to other functions, can be nested inside other functions, and more.如上例所示,内部函数make()是从外部函数makeCounter()返回的。因此,myCounter的值是内部的make()函数(第14行),调用myCounter有效地调用make()。在JavaScript中,可以将函数分配给变量,将其作为参数传递给其他函数,也可以嵌套在其他函数中,等等。
You‘ll also notice that the inner function
make()
is still able to access the value ofcounter
variable defined in the outer function, even though themakeCounter()
function has already finished executing (line no-14). It happens because functions in JavaScript form closures. Closures internally store references to their outer variables, and can access and update their values.您还会注意到,即使makeCounter()函数已经完成执行(第14行),内部函数make()仍然能够访问在外部函数中定义的counter变量的值。发生这种情况是因为JavaScript中的函数形成了闭包。闭包内部存储对其外部变量的引用,并且可以访问和更新其值。
In the example above, the
make()
function is a closure whose code refers to the outer variablecounter
. This implies that whenever themake()
function is invoked, the code inside it is able to access and update thecounter
variable because it is stored in the closure.在上面的示例中,make()函数是一个闭包,其代码引用了外部变量counter。这意味着无论何时调用make()函数,由于其存储在闭包中,因此其内部的代码能够访问和更新counter变量。
Finally, since the outer function has finished executing, no other part of the code can access or manipulate the
counter
variable. Only the inner function has exclusive access to it.最后,由于外部函数已完成执行,因此代码的其他部分都无法访问或操纵counter变量。仅内部函数对其具有独占访问权。
The previous example can also be written using anonymous function expression, like this:
前面的示例也可以使用匿名函数表达式编写,如下所示:
// Anonymous function expression
var myCounter = (function() {
var counter = 0;
// Nested anonymous function
return function() {
counter += 1;
return counter;
}
})();
console.log(myCounter()); // Prints: 1
console.log(myCounter()); // Prints: 2
Tip: In JavaScript, all functions have access to the global scope, as well as the scope above them. As JavaScript supports nested functions, this typically means that the nested functions have access to any value declared in a higher scope including its parent function‘s scope.
提示:在JavaScript中,所有函数都可以访问全局范围以及它们上方的范围。由于JavaScript支持嵌套函数,因此通常意味着嵌套函数可以访问在较高范围(包括其父函数的范围)中声明的任何值。
Note: The global variables live as long as your application (i.e. your web page) lives. Whereas, the local variables have a short life span, they are created when the function is invoked, and destroyed as soon as the function is finished executing.
注意:全局变量的寿命与您的应用程序(即您的网页)的寿命一样长。局部变量的寿命很短,它们是在调用函数时创建的,并在函数执行完毕后立即销毁。
Here we will create a variable
secret
and protect it from being directly manipulated from outside code using closure. We will also create getter and setter functions to get and set its value.在这里,我们将创建一个变量secret,并防止它使用闭包直接从外部代码中进行操作。我们还将创建getter和setter函数以获取并设置其值。
Additionally, the setter function will also perform a quick check whether the specified value is a number or not, and if it is not it will not change the variable value.
另外,setter函数还将快速检查指定的值是否为数字,如果不是,则不会更改变量值。
var getValue, setValue;
// Self-executing function
(function() {
var secret = 0;
// Getter function
getValue = function() {
return secret;
};
// Setter function
setValue = function(x) {
if(typeof x === "number") {
secret = x;
}
};
}());
// Calling the functions
console.log(getValue()); // Returns: 0
setValue(10);
console.log(getValue()); // Returns: 10
setValue(null);
console.log(getValue()); // Returns: 10
Tip: Self-executing functions are also called immediately invoked function expression (IIFE), immediately executed function, or self-executing anonymous function.
提示:自执行函数也称为立即调用函数表达式(IIFE),立即执行的函数或自我执行的匿名函数。
let makeIncrement, makeDecrease;
function make() {
let count;
makeIncrement = function() {
return ++count;
};
makeDecrease = function() {
return --count;
}
count = 1;
console.log(`inside make, call to makeIncrement(): ${makeIncrement()}`);
}
make(); // 2
console.log(`call to makeDecrease(): ${makeDecrease()}`); // 1 (--count)
console.log(`call to makeDecrease(): ${makeDecrease()}`); // 0 (--count)
console.log(`call to makeIncrement(): ${makeIncrement()}`); // 1 (++count)
console.log(`call to makeIncrement(): ${makeIncrement()}`); // 2 (++count)
// Reference to an unbound variable
let moduleSet = {
x: 42,
getX: function() {
return this.x;
}
};
let unboundGetX= moduleSet.getX;
console.log(unboundGetX());
// This function gets invoked at the gloal scope
// emits undefined as ‘x‘ is not specified in global scope
// 函数在全局范围内被调用
// 发出undefined,因为未在全局范围内指定‘x‘
// specify object moduleSet as the closure
// 指定对象moduleSet为闭包
let boundGetX = unboundGetX.bind(moduleSet);
console.log(boundGetX()); // emits 42
Understanding closures in depth
原文:https://www.cnblogs.com/PrimerPlus/p/12844336.html