您将如何向了解其闭包概念(例如函数,变量等)的人解释JavaScript闭包,但却不了解闭包本身?
我已经在Wikipedia上看到了Scheme示例,但是不幸的是它没有帮助。
您将如何向了解其闭包概念(例如函数,变量等)的人解释JavaScript闭包,但却不了解闭包本身?
我已经在Wikipedia上看到了Scheme示例,但是不幸的是它没有帮助。
The author of Closures has explained closures pretty well, explaining the reason why we need them and also explaining LexicalEnvironment which is necessary to understanding closures.
Here is the summary:
What if a variable is accessed, but it isn’t local? Like here:
In this case, the interpreter finds the variable in the
outer LexicalEnvironment
object.
The process consists of two steps:
When a function is created, it gets a hidden property, named [[Scope]], which references the current LexicalEnvironment.
If a variable is read, but can not be found anywhere, an error is generated.
Nested functions
Functions can be nested one inside another, forming a chain of LexicalEnvironments which can also be called a scope chain.
So, function g has access to g, a and f.
Closures
A nested function may continue to live after the outer function has finished:
Marking up LexicalEnvironments:
As we see, this.say
is a property in the user object, so it continues to live after User completed.
And if you remember, when this.say
is created, it (as every function) gets an internal reference this.say.[[Scope]]
to the current LexicalEnvironment. So, the LexicalEnvironment of the current User execution stays in memory. All variables of User also are its properties, so they are also carefully kept, not junked as usually.
The whole point is to ensure that if the inner function wants to access an outer variable in the future, it is able to do so.
To summarize:
这称为关闭。
一个六岁孩子的答案(假设他知道什么是函数,什么是变量以及什么数据):
函数可以返回数据。您可以从函数返回的一种数据是另一种函数。返回该新函数时,创建该函数的函数中使用的所有变量和参数都不会消失。而是,该父函数“关闭”。换句话说,除了返回的功能外,什么都看不到它,也看不到它使用的变量。该新函数具有特殊的功能,可以回顾创建它的函数内部并查看其中的数据。
function the_closure() {
var x = 4;
return function () {
return x; // Here, we look back inside the_closure for the value of x
}
}
var myFn = the_closure();
myFn(); //=> 4
解释它的另一种非常简单的方法是在范围上:
每当您在较大范围内创建较小范围时,较小范围将始终能够看到较大范围中的内容。
我不明白为什么答案在这里这么复杂。
这是一个闭包:
var a = 42;
function b() { return a; }
是。您可能一天使用多次。
没有理由相信闭包是解决特定问题的复杂设计方法。不,从函数声明的位置(不运行)的角度来看,闭包只是使用来自更高范围的变量。
现在,它允许您执行的操作会更加壮观,请参阅其他答案。
dlaliberte第一点的示例:
闭包不仅在您返回内部函数时创建。实际上,封闭函数根本不需要返回。您可以改为将内部函数分配给外部作用域中的变量,或将其作为参数传递给可以立即使用的另一个函数。因此,在调用封闭函数时,封闭函数的关闭可能已经存在,因为任何内部函数都可以在调用它后立即对其进行访问。
var i;
function foo(x) {
var tmp = 3;
i = function (y) {
console.log(x + y + (++tmp));
}
}
foo(2);
i(3);
我知道已经有很多解决方案,但是我猜想这个小而简单的脚本可以用来说明这个概念:
// makeSequencer will return a "sequencer" function
var makeSequencer = function() {
var _count = 0; // not accessible outside this function
var sequencer = function () {
return _count++;
}
return sequencer;
}
var fnext = makeSequencer();
var v0 = fnext(); // v0 = 0;
var v1 = fnext(); // v1 = 1;
var vz = fnext._count // vz = undefined
闭包是内部函数可以访问其外部函数中的变量的地方。这可能是闭包最简单的单行解释。
我如何向六岁的孩子解释:
您知道大人如何拥有房屋,他们称之为房屋吗?当妈妈有孩子时,孩子实际上并不拥有任何东西,对吗?但是它的父母拥有一所房子,因此只要有人问孩子“你的房子在哪里?”,他/她就可以回答“那所房子!”,并指向其父母的房子。“关闭”是孩子始终(即使在国外)能够说出自己有房屋的能力,即使实际上这是父母的财产。
前一段时间,我写了一篇博客文章解释了闭包。这就是我说的关于闭包的原因,因为您想要一个闭包。
闭包是一种使函数具有永久性私有变量的方法,也就是说,只有一个函数才知道的变量,它可以在其中跟踪以前运行时的信息。
从这种意义上讲,它们使函数的行为有点像具有私有属性的对象。
全文:
闭包很难解释,因为闭包用于使某些行为正常工作,每个人都希望它们能正常工作。我发现解释它们的最佳方法(以及我了解它们的方法)是想象没有它们的情况:
var bind = function(x) {
return function(y) { return x + y; };
}
var plus5 = bind(5);
console.log(plus5(3));
如果JavaScript 不知道闭包,在这里会发生什么?只需将最后一行的调用替换为其方法主体(基本上是函数调用所做的工作),您将获得:
console.log(x + 3);
现在,的定义在x
哪里?我们没有在当前范围内对其进行定义。唯一的解决方案是plus5
随身携带其范围(或更确切地说,其父级的范围)。这种方式x
定义明确,并绑定到值5。
好吧,6岁的瓶盖粉丝。您是否想听到最简单的闭包示例?
让我们想象下一个情况:驾驶员坐在汽车上。那辆车在飞机上。飞机在机场。驾驶员即使在飞机离开机场后也无法进入汽车外部但在飞机内部的东西,这是封闭的。而已。27岁时,请查看更详细的说明或以下示例。
这是将飞机上的故事转换为代码的方法。
var plane = function(defaultAirport) {
var lastAirportLeft = defaultAirport;
var car = {
driver: {
startAccessPlaneInfo: function() {
setInterval(function() {
console.log("Last airport was " + lastAirportLeft);
}, 2000);
}
}
};
car.driver.startAccessPlaneInfo();
return {
leaveTheAirport: function(airPortName) {
lastAirportLeft = airPortName;
}
}
}("Boryspil International Airport");
plane.leaveTheAirport("John F. Kennedy");
JavaScript中的每个函数都维护与其外部词法环境的链接。词汇环境是作用域中所有名称(例如变量,参数)及其值的映射。
因此,每当您看到function
关键字时,该函数内部的代码都可以访问该函数外部声明的变量。
function foo(x) {
var tmp = 3;
function bar(y) {
console.log(x + y + (++tmp)); // will log 16
}
bar(10);
}
foo(2);
这将记录下来16
,因为函数bar
关闭了参数x
和变量tmp
,两者都存在于外部函数的词法环境中foo
。
Function bar
及其与函数的词法环境的链接foo
是一个闭包。
一个函数不必为了创建一个闭包而返回。仅仅凭借其声明,每个函数都会在其封闭的词法环境中关闭,从而形成一个闭合。
function foo(x) {
var tmp = 3;
return function (y) {
console.log(x + y + (++tmp)); // will also log 16
}
}
var bar = foo(2);
bar(10); // 16
bar(10); // 17
上面的函数也会记录16,因为里面的代码bar
仍然可以引用参数x
和变量tmp
,即使它们不再直接在范围内。
但是,由于tmp
仍在内部bar
的封闭中徘徊,因此可以对其进行递增。每次调用时,它都会增加bar
。
关闭的最简单示例是:
var a = 10;
function test() {
console.log(a); // will output 10
console.log(b); // will output 6
}
var b = 6;
test();
When a JavaScript function is invoked, a new execution context ec
is created. Together with the function arguments and the target object, this execution context also receives a link to the lexical environment of the calling execution context, meaning the variables declared in the outer lexical environment (in the above example, both a
and b
) are available from ec
.
Every function creates a closure, because every function has a link to its outer lexical environment.
Note that variables themselves are visible from within a closure, not copies.
我只是将它们指向Mozilla Closures页面。这是我发现的关于闭包基础知识和实际用法的最佳,最简洁明了的解释。强烈建议任何学习JavaScript的人使用。
是的,我什至推荐给6岁的孩子使用-如果6岁的孩子正在学习闭包,那么可以随时理解本文提供的简洁明了的逻辑是合乎逻辑的。