JavaScriptclosures如何工作?

你如何解释JavaScript闭包给了解它们所包含的概念(例如函数,variables之类)的人,但是自己并不理解闭包?

我已经看到维基百科给出的Scheme示例 ,但不幸的是它没有帮助。

初学者的JavaScriptclosures

Morris在星期二提交,2006-02-21 10:19。 自社区编辑。

closures不是魔术

本页面解释了闭包,以便程序员可以理解它们 – 使用正在运行的JavaScript代码。 这不是大师或function程序员。

一旦核心概念得到修复,closures并不难理解。 但是,通过阅读任何学术论文或学术导向的信息,他们是不可能理解的!

本文面向具有某种主stream语言编程经验的程序员,他们可以阅读以下JavaScript函数:

function sayHello(name) { var text = 'Hello ' + name; var say = function() { console.log(text); } say(); } sayHello('Joe'); 

无论何时在另一个函数中看到函数关键字,内部函数都可以访问外部函数中的variables。

 function foo(x) { var tmp = 3; function bar(y) { console.log(x + y + (++tmp)); // will log 16 } bar(10); } foo(2); 

前言:当问题是:

就像老艾伯特所说的那样:“如果你不能解释给六岁的孩子,你自己就不明白了。”那么我试着向一位27岁的朋友解释JS封锁,并且彻底失败了。

有人可以认为我对这个问题很感兴趣吗?

我很确定我是唯一一个试图从字面上理解最初的问题的人之一。 从那时起,这个问题已经多次发生了变化,所以现在我的答案似乎变得非常愚蠢和不合适。 希望这个故事的总体思路对一些人来说仍然很有趣。


在解释困难的概念时,我是比喻和比喻的忠实粉丝,所以让我试试一个故事吧。

很久以前:

有一个公主…

 function princess() { 

她住在一个充满冒险精彩的世界。 她遇到了她的白马王子,骑着独angular兽骑着她的世界,与龙战斗,遇到说话的动物,以及许多其他的幻想事物。

  var adventures = []; function princeCharming() { /* ... */ } var unicorn = { /* ... */ }, dragons = [ /* ... */ ], squirrel = "Hello!"; /* ... */ 

但她总是不得不回到沉闷的家务和大人的世界。

  return { 

而且她经常告诉他们她最新的冒险公主。

  story: function() { return adventures[adventures.length - 1]; } }; } 

但他们只能看到一个小女孩

 var littleGirl = princess(); 

讲述关于魔法和幻想的故事。

 littleGirl.story(); 

即使成年人知道真正的公主,他们也不会相信独angular兽或龙,因为他们永远看不到他们。 大人们说,他们只存在于小女孩的想象之中。

但我们知道真相, 那个公主里面的小女孩

…真的是一个里面有一个小女孩的公主。

认真思考这个问题,我们应该了解一个典型的6岁孩子能够认知的能力,虽然公认的是,对JavaScript感兴趣的人不是那么典型。

关于儿童发展:5至7年说:

你的孩子将能够遵循两步走向。 例如,如果你对你的孩子说,“去厨房给我一个垃圾袋”,他们将能够记住这个方向。

我们可以用这个例子来解释闭包,如下所示:

厨房是一个封闭的,有一个局部variables,称为trashBags 。 在厨房里有一个叫做getTrashBag的function,它得到一个垃圾袋并将其返回。

我们可以用JavaScript编写这样的代码:

 function makeKitchen () { var trashBags = ['A', 'B', 'C']; // only 3 at first return { getTrashBag: function() { return trashBags.pop(); } }; } var kitchen = makeKitchen(); kitchen.getTrashBag(); // returns trash bag C kitchen.getTrashBag(); // returns trash bag B kitchen.getTrashBag(); // returns trash bag A 

进一步的观点解释了为什么封闭是有趣的:

  • 每次调用makeKitchen() ,都会创build一个新的闭包,并使用它自己的trashBags
  • trashBagsvariables在每个厨房的内部是局部的,并且不能在外部访问,但getTrashBag属性的内部函数可以访问它。
  • 每个函数调用都会创build一个闭包,但除非可以从闭包之外调用可以访问闭包内部的内部函数,否则不需要将闭包保留在周围。 用getTrashBag函数返回对象在这里做。

稻草人

我需要知道一个button被点击了多less次,每做一次点击操作…

相当明显的解决scheme

 // Declare counter outside event handler's scope var counter = 0; var element = document.getElementById('button'); element.addEventListener("click", function() { // Increment outside counter counter++; if (counter === 3) { // Do something every third time console.log("Third time's the charm!"); // Reset counter counter = 0; } }); 
 <button id="button">Click Me!</button> 

closures是很难解释的,因为它们被用来做一些行为,每个人都直觉地期望无论如何工作。 我发现解释它们的最好方法(以及学习他们所做的事情的方式)是想象没有它们的情况:

  var bind = function(x) { return function(y) { return x + y; }; } var plus5 = bind(5); console.log(plus5(3)); 

这是为了澄清在其他一些答案中出现的关于闭包的几个(可能的)误解。

  • 闭包不仅在您返回内部函数时创build。 实际上,封闭函数根本不需要返回,以便创build闭包。 你也可以把你的内部函数赋给一个外部variables的variables,或者把它作为一个parameter passing给另一个函数,这个函数可以被立即调用,或者随后调用。 因此, 只要封闭函数被调用,封闭函数的closures就可能被创build因为任何内部函数都可以在封闭函数返回之前或之后调用内部函数时访问该闭包。
  • 闭包不引用其范围中variables的副本。 variables本身是闭包的一部分,所以访问其中一个variables时所看到的值就是访问时的最新值。 这就是为什么在循环内创build的内部函数可能会非常棘手,因为在创build或调用函数时,每个函数都可以访问相同的外部variables,而不是抓取variables的副本。
  • 闭包中的“variables”包括在函数中声明的任何命名函数。 他们还包括这个function的论点。 封闭也可以访问其封闭的variables,一直到全球范围。
  • 闭包使用内存,但是它们不会导致内存泄漏,因为JavaScript本身会清除自己的未引用的循环结构。 当无法断开引用闭包的DOM属性值时,将创build涉及闭包的Internet Explorer内存泄漏,从而保持对可能的圆形结构的引用。

OK, 6-year-old closures fan. Do you want to hear the simplest example of closure?

Let's imagine the next situation: a driver is sitting in a car. That car is inside a plane. Plane is in the airport. The ability of driver to access things outside his car, but inside the plane, even if that plane leaves an airport, is a closure. 而已。 When you turn 27, look at the more detailed explanation or at the example below.

Here is how I can convert my plane story into the code.

 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"); 

A closure is much like an object. It gets instantiated whenever you call a function.

The scope of a closure in JavaScript is lexical, which means that everything that is contained within the function the closure belongs to, has access to any variable that is in it.

A variable is contained in the closure if you

  1. assign it with var foo=1; 要么
  2. just write var foo;

If an inner function (a function contained inside another function) accesses such a variable without defining it in its own scope with var, it modifies the content of the variable in the outer closure .

A closure outlives the runtime of the function that spawned it. If other functions make it out of the closure/scope in which they are defined (for instance as return values), those will continue to reference that closure .

  function example(closure) { // define somevariable to live in the closure of example var somevariable = 'unchanged'; return { change_to: function(value) { somevariable = value; }, log: function(value) { console.log('somevariable of closure %s is: %s', closure, somevariable); } } } closure_one = example('one'); closure_two = example('two'); closure_one.log(); closure_two.log(); closure_one.change_to('some new value'); closure_one.log(); closure_two.log(); 

产量

 somevariable of closure one is: unchanged somevariable of closure two is: unchanged somevariable of closure one is: some new value somevariable of closure two is: unchanged 

I wrote a blog post a while back explaining closures. Here's what I said about closures in terms of why you'd want one.

Closures are a way to let a function have persistent, private variables – that is, variables that only one function knows about, where it can keep track of info from previous times that it was run.

In that sense, they let a function act a bit like an object with private attributes.

Full post:

So what are these closure thingys?

How I'd explain it to a six-year-old:

You know how grown-ups can own a house, and they call it home? When a mom has a child, the child doesn't really own anything, right? But its parents own a house, so whenever someone asks the child "Where's your home?", he/she can answer "that house!", and point to the house of its parents. A "Closure" is the ability of the child to always (even if abroad) be able to say it has a home, even though it's really the parent's who own the house.

Closures are simple:

The following simple example covers all the main points of JavaScript closures. *

Here is a factory that produces calculators that can add and multiply:

 function make_calculator() { var n = 0; // this calculator stores a single number n return { add: function(a) { n += a; return n; }, multiply: function(a) { n *= a; return n; } }; } first_calculator = make_calculator(); second_calculator = make_calculator(); first_calculator.add(3); // returns 3 second_calculator.add(400); // returns 400 first_calculator.multiply(11); // returns 33 second_calculator.multiply(10); // returns 4000 

The key point: Each call to make_calculator creates a new local variable n , which continues to be usable by that calculator's add and multiply functions long after make_calculator returns.

If you are familiar with stack frames, these calculators seem strange: How can they keep accessing n after make_calculator returns? The answer is to imagine that JavaScript doesn't use "stack frames", but instead uses "heap frames", which can persist after the function call that made them returns.

Inner functions like add and multiply , which access variables declared in an outer function ** , are called closures .

That is pretty much all there is to closures.


* For example, it covers all the points in the "Closures for Dummies" article given in another answer , except example 6, which simply shows that variables can be used before they are declared, a nice fact to know but completely unrelated to closures. It also covers all the points in the accepted answer , except for the points (1) that functions copy their arguments into local variables (the named function arguments), and (2) that copying numbers creates a new number, but copying an object reference gives you another reference to the same object. These are also good to know but again completely unrelated to closures. It is also very similar to the example in this answer but a bit shorter and less abstract. It does not cover the point of this answer or this comment , which is that JavaScript makes it difficult to plug the current value of a loop variable into your inner function: The "plugging in" step can only be done with a helper function that encloses your inner function and is invoked on each loop iteration. (Strictly speaking, the inner function accesses the helper function's copy of the variable, rather than having anything plugged in.) Again, very useful when creating closures, but not part of what a closure is or how it works. There is additional confusion due to closures working differently in functional languages like ML, where variables are bound to values rather than to storage space, providing a constant stream of people who understand closures in a way (namely the "plugging in" way) that is simply incorrect for JavaScript, where variables are always bound to storage space, and never to values.

** Any outer function, if several are nested, or even in the global context, as this answer points out clearly.

Can you explain closures to a 5-year-old?*

I still think Google's explanation works very well and is concise:

 /* * When a function is defined in another function and it * has access to the outer function's context even after * the outer function returns. * * An important concept to learn in JavaScript. */ function outerFunction(someNum) { var someString = 'Hey!'; var content = document.getElementById('content'); function innerFunction() { content.innerHTML = someNum + ': ' + someString; content = null; // Internet Explorer memory leak for DOM reference } innerFunction(); } outerFunction(1);​ 

Proof that this example creates a closure even if the inner function doesn't return

*AC# question

I tend to learn better by GOOD/BAD comparisons. I like to see working code followed by non-working code that someone is likely to encounter. I put together a jsFiddle that does a comparison and tries to boil down the differences to the simplest explanations I could come up with.

Closures done right:

 console.log('CLOSURES DONE RIGHT'); var arr = []; function createClosure(n) { return function () { return 'n = ' + n; } } for (var index = 0; index < 10; index++) { arr[index] = createClosure(index); } for (var index in arr) { console.log(arr[index]()); } 
  • In the above code createClosure(n) is invoked in every iteration of the loop. Note that I named the variable n to highlight that it is a new variable created in a new function scope and is not the same variable as index which is bound to the outer scope.

  • This creates a new scope and n is bound to that scope; this means we have 10 separate scopes, one for each iteration.

  • createClosure(n) returns a function that returns the n within that scope.

  • Within each scope n is bound to whatever value it had when createClosure(n) was invoked so the nested function that gets returned will always return the value of n that it had when createClosure(n) was invoked.

Closures done wrong:

 console.log('CLOSURES DONE WRONG'); function createClosureArray() { var badArr = []; for (var index = 0; index < 10; index++) { badArr[index] = function () { return 'n = ' + index; }; } return badArr; } var badArr = createClosureArray(); for (var index in badArr) { console.log(badArr[index]()); } 
  • In the above code the loop was moved within the createClosureArray() function and the function now just returns the completed array, which at first glance seems more intuitive.

  • What might not be obvious is that since createClosureArray() is only invoked once only one scope is created for this function instead of one for every iteration of the loop.

  • Within this function a variable named index is defined. The loop runs and adds functions to the array that return index . Note that index is defined within the createClosureArray function which only ever gets invoked one time.

  • Because there was only one scope within the createClosureArray() function, index is only bound to a value within that scope. In other words, each time the loop changes the value of index , it changes it for everything that references it within that scope.

  • All of the functions added to the array return the SAME index variable from the parent scope where it was defined instead of 10 different ones from 10 different scopes like the first example. The end result is that all 10 functions return the same variable from the same scope.

  • After the loop finished and index was done being modified the end value was 10, therefore every function added to the array returns the value of the single index variable which is now set to 10.

结果

CLOSURES DONE RIGHT
n = 0
n = 1
n = 2
n = 3
n = 4
n = 5
n = 6
n = 7
n = 8
n = 9

CLOSURES DONE WRONG
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10

Wikipedia on closures :

In computer science, a closure is a function together with a referencing environment for the nonlocal names (free variables) of that function.

Technically, in JavaScript , every function is a closure . It always has an access to variables defined in the surrounding scope.

Since scope-defining construction in JavaScript is a function , not a code block like in many other languages, what we usually mean by closure in JavaScript is a function working with nonlocal variables defined in already executed surrounding function .

Closures are often used for creating functions with some hidden private data (but it's not always the case).

 var db = (function() { // Create a hidden object, which will hold the data // it's inaccessible from the outside. var data = {}; // Make a function, which will provide some access to the data. return function(key, val) { if (val === undefined) { return data[key] } // Get else { return data[key] = val } // Set } // We are calling the anonymous surrounding function, // returning the above inner function, which is a closure. })(); db('x') // -> undefined db('x', 1) // Set x to 1 db('x') // -> 1 // It's impossible to access the data object itself. // We are able to get or set individual it. 

EMS

The example above is using an anonymous function, which was executed once. But it does not have to be. It can be named (eg mkdb ) and executed later, generating a database function each time it is invoked. Every generated function will have its own hidden database object. Another usage example of closures is when we don't return a function, but an object containing multiple functions for different purposes, each of those function having access to the same data.

I put together an interactive JavaScript tutorial to explain how closures work. What's a Closure?

Here's one of the examples:

 var create = function (x) { var f = function () { return x; // We can refer to x here! }; return f; }; // 'create' takes one argument, creates a function var g = create(42); // g is a function that takes no arguments now var y = g(); // y is 42 here 

The children will always remember the secrets they have shared with their parents, even after their parents are gone. This is what closures are for functions.

The secrets for JavaScript functions are the private variables

 var parent = function() { var name = "Mary"; // secret } 

Every time you call it, local variable "name" is created and given name "Mary". And every time the function exits the variable is lost and the name is forgotten.

As you may guess, because the variables are re-created every time the function is called, and nobody else will know them, there must be a secret place where they are stored. It could be called Chamber of Secrets or stack or local scope but it doesn't really matter. We know they are there, somewhere, hidden in the memory.

But, in JavaScript there is this very special thing that functions which are created inside other functions, can also know the local variables of their parents and keep them as long as they live.

 var parent = function() { var name = "Mary"; var child = function(childName) { // I can also see that "name" is "Mary" } } 

So, as long as we are in the parent -function, it can create one or more child functions which do share the secret variables from the secret place.

But the sad thing is, if the child is also a private variable of its parent function, it would also die when the parent ends, and the secrets would die with them.

So to live, the child has to leave before it's too late

 var parent = function() { var name = "Mary"; var child = function(childName) { return "My name is " + childName +", child of " + name; } return child; // child leaves the parent -> } var child = parent(); // < - and here it is outside 

And now, even though Mary is "no longer running", the memory of her is not lost and her child will always remember her name and other secrets they shared during their time together.

So, if you call the child "Alice", she will respond

 child("Alice") => "My name is Alice, child of Mary" 

That's all there is to tell.

I do not understand why the answers are so complex here.

Here is a closure:

 var a = 42; function b() { return a; } 

是。 You probably use that many times a day.

There is no reason to believe closures are a complex design hack to address specific problems. No, closures are just about using a variable that comes from a higher scope from the perspective of where the function was declared (not run) .

Now what it allows you to do can be more spectacular, see other answers.

Example for the first point by dlaliberte:

A closure is not only created when you return an inner function. In fact, the enclosing function does not need to return at all. You might instead assign your inner function to a variable in an outer scope, or pass it as an argument to another function where it could be used immediately. Therefore, the closure of the enclosing function probably already exists at the time that enclosing function was called since any inner function has access to it as soon as it is called.

 var i; function foo(x) { var tmp = 3; i = function (y) { console.log(x + y + (++tmp)); } } foo(2); i(3); 

You're having a sleep over and you invite Dan. You tell Dan to bring one XBox controller.

Dan invites Paul. Dan asks Paul to bring one controller. How many controllers were brought to the party?

 function sleepOver(howManyControllersToBring) { var numberOfDansControllers = howManyControllersToBring; return function danInvitedPaul(numberOfPaulsControllers) { var totalControllers = numberOfDansControllers + numberOfPaulsControllers; return totalControllers; } } var howManyControllersToBring = 1; var inviteDan = sleepOver(howManyControllersToBring); // The only reason Paul was invited is because Dan was invited. // So we set Paul's invitation = Dan's invitation. var danInvitedPaul = inviteDan(howManyControllersToBring); alert("There were " + danInvitedPaul + " controllers brought to the party."); 

A closure is where an inner function has access to variables in its outer function. That's probably the simplest one-line explanation you can get for closures.

I know there are plenty of solutions already, but I guess that this small and simple script can be useful to demonstrate the concept:

 // 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 

JavaScript functions can access their:

  1. 参数
  2. Locals (that is, their local variables and local functions)
  3. Environment, which includes:
    • globals, including the DOM
    • anything in outer functions

If a function accesses its environment, then the function is a closure.

Note that outer functions are not required, though they do offer benefits I don't discuss here. By accessing data in its environment, a closure keeps that data alive. In the subcase of outer/inner functions, an outer function can create local data and eventually exit, and yet, if any inner function(s) survive after the outer function exits, then the inner function(s) keep the outer function's local data alive.

Example of a closure that uses the global environment:

Imagine that the Stack Overflow Vote-Up and Vote-Down button events are implemented as closures, voteUp_click and voteDown_click, that have access to external variables isVotedUp and isVotedDown, which are defined globally. (For simplicity's sake, I am referring to StackOverflow's Question Vote buttons, not the array of Answer Vote buttons.)

When the user clicks the VoteUp button, the voteUp_click function checks whether isVotedDown == true to determine whether to vote up or merely cancel a down vote. Function voteUp_click is a closure because it is accessing its environment.

 var isVotedUp = false; var isVotedDown = false; function voteUp_click() { if (isVotedUp) return; else if (isVotedDown) SetDownVote(false); else SetUpVote(true); } function voteDown_click() { if (isVotedDown) return; else if (isVotedUp) SetUpVote(false); else SetDownVote(true); } function SetUpVote(status) { isVotedUp = status; // Do some CSS stuff to Vote-Up button } function SetDownVote(status) { isVotedDown = status; // Do some CSS stuff to Vote-Down button } 

All four of these functions are closures as they all access their environment.

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? 像这样:

在这里输入图像说明

In this case, the interpreter finds the variable in the outer LexicalEnvironment object.

The process consists of two steps:

  1. First, when a function f is created, it is not created in an empty space. There is a current LexicalEnvironment object. In the case above, it's window (a is undefined at the time of function creation).

在这里输入图像说明

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.

总结:

  1. The inner function keeps a reference to the outer LexicalEnvironment.
  2. The inner function may access variables from it any time even if the outer function is finished.
  3. The browser keeps the LexicalEnvironment and all its properties (variables) in memory until there is an inner function which references it.

This is called a closure.

(You may also want to read What is a practical use for a closure in JavaScript? )

As a father of a 6-year-old, currently teaching young children (and a relative novice to coding with no formal education so corrections will be required), I think the lesson would stick best through hands-on play. If the 6-year-old is ready to understand what a closure is, then they are old enough to have a go themselves. I'd suggest pasting the code into jsfiddle.net, explaining a bit, and leaving them alone to concoct a unique song. The explanatory text below is probably more appropriate for a 10 year old.

 function sing(person) { var firstPart = "There was " + person + " who swallowed "; var fly = function() { var creature = "a fly"; var result = "Perhaps she'll die"; alert(firstPart + creature + "\n" + result); }; var spider = function() { var creature = "a spider"; var result = "that wiggled and jiggled and tickled inside her"; alert(firstPart + creature + "\n" + result); }; var bird = function() { var creature = "a bird"; var result = "How absurd!"; alert(firstPart + creature + "\n" + result); }; var cat = function() { var creature = "a cat"; var result = "Imagine That!"; alert(firstPart + creature + "\n" + result); }; fly(); spider(); bird(); cat(); } var person="an old lady"; sing(person); 

INSTRUCTIONS

DATA: Data is a collection of facts. It can be numbers, words, measurements, observations or even just descriptions of things. You can't touch it, smell it or taste it. You can write it down, speak it and hear it. You could use it to create touch smell and taste using a computer. It can be made useful by a computer using code.

CODE: All the writing above is called code . It is written in JavaScript.

JAVASCRIPT: JavaScript is a language. Like English or French or Chinese are languages. There are lots of languages that are understood by computers and other electronic processors. For JavaScript to be understood by a computer it needs an interpreter. Imagine if a teacher who only speaks Russian comes to teach your class at school. When the teacher says "все садятся", the class would not understand. But luckily you have a Russian pupil in your class who tells everyone this means "everybody sit down" – so you all do. The class is like a computer and the Russian pupil is the interpreter. For JavaScript the most common interpreter is called a browser.

BROWSER: When you connect to the Internet on a computer, tablet or phone to visit a website, you use a browser. Examples you may know are Internet Explorer, Chrome, Firefox and Safari. The browser can understand JavaScript and tell the computer what it needs to do. The JavaScript instructions are called functions.

FUNCTION: A function in JavaScript is like a factory. It might be a little factory with only one machine inside. Or it might contain many other little factories, each with many machines doing different jobs. In a real life clothes factory you might have reams of cloth and bobbins of thread going in and T-shirts and jeans coming out. Our JavaScript factory only processes data, it can't sew, drill a hole or melt metal. In our JavaScript factory data goes in and data comes out.

All this data stuff sounds a bit boring, but it is really very cool; we might have a function that tells a robot what to make for dinner. Let's say I invite you and your friend to my house. You like chicken legs best, I like sausages, your friend always wants what you want and my friend does not eat meat.

I haven't got time to go shopping, so the function needs to know what we have in the fridge to make decisions. Each ingredient has a different cooking time and we want everything to be served hot by the robot at the same time. We need to provide the function with the data about what we like, the function could 'talk' to the fridge, and the function could control the robot.

A function normally has a name, parentheses and braces. 喜欢这个:

 function cookMeal() { /* STUFF INSIDE THE FUNCTION */ } 

Note that /*...*/ and // stop code being read by the browser.

NAME: You can call a function just about whatever word you want. The example "cookMeal" is typical in joining two words together and giving the second one a capital letter at the beginning – but this is not necessary. It can't have a space in it, and it can't be a number on its own.

PARENTHESES: "Parentheses" or () are the letter box on the JavaScript function factory's door or a post box in the street for sending packets of information to the factory. Sometimes the postbox might be marked for example cookMeal(you, me, yourFriend, myFriend, fridge, dinnerTime) , in which case you know what data you have to give it.

BRACES: "Braces" which look like this {} are the tinted windows of our factory. From inside the factory you can see out, but from the outside you can't see in.

THE LONG CODE EXAMPLE ABOVE

Our code begins with the word function , so we know that it is one! Then the name of the function sing – that's my own description of what the function is about. Then parentheses () . The parentheses are always there for a function. Sometimes they are empty, and sometimes they have something in. This one has a word in: (person) . After this there is a brace like this { . This marks the start of the function sing() . It has a partner which marks the end of sing() like this }

 function sing(person) { /* STUFF INSIDE THE FUNCTION */ } 

So this function might have something to do with singing, and might need some data about a person. It has instructions inside to do something with that data.

Now, after the function sing() , near the end of the code is the line

 var person="an old lady"; 

VARIABLE: The letters var stand for "variable". A variable is like an envelope. On the outside this envelope is marked "person". On the inside it contains a slip of paper with the information our function needs, some letters and spaces joined together like a piece of string (it's called a string) that make a phrase reading "an old lady". Our envelope could contain other kinds of things like numbers (called integers), instructions (called functions), lists (called arrays ). Because this variable is written outside of all the braces {} , and because you can see out through the tinted windows when you are inside the braces, this variable can be seen from anywhere in the code. We call this a 'global variable'.

GLOBAL VARIABLE: person is a global variable, meaning that if you change its value from "an old lady" to "a young man", the person will keep being a young man until you decide to change it again and that any other function in the code can see that it's a young man. Press the F12 button or look at the Options settings to open the developer console of a browser and type "person" to see what this value is. Type person="a young man" to change it and then type "person" again to see that it has changed.

After this we have the line

 sing(person); 

This line is calling the function, as if it were calling a dog

"Come on sing , Come and get person !"

When the browser has loaded the JavaScript code an reached this line, it will start the function. I put the line at the end to make sure that the browser has all the information it needs to run it.

Functions define actions – the main function is about singing. It contains a variable called firstPart which applies to the singing about the person that applies to each of the verses of the song: "There was " + person + " who swallowed". If you type firstPart into the console, you won't get an answer because the variable is locked up in a function – the browser can't see inside the tinted windows of the braces.

CLOSURES: The closures are the smaller functions that are inside the big sing() function. The little factories inside the big factory. They each have their own braces which mean that the variables inside them can't be seen from the outside. That's why the names of the variables ( creature and result ) can be repeated in the closures but with different values. If you type these variable names in the console window, you won't get its value because it's hidden by two layers of tinted windows.

The closures all know what the sing() function's variable called firstPart is, because they can see out from their tinted windows.

After the closures come the lines

 fly(); spider(); bird(); cat(); 

The sing() function will call each of these functions in the order they are given. Then the sing() function's work will be done.

Okay, talking with a 6-year old child, I would possibly use following associations.

Imagine – you are playing with your little brothers and sisters in the entire house, and you are moving around with your toys and brought some of them into your older brother's room. After a while your brother returned from the school and went to his room, and he locked inside it, so now you could not access toys left there anymore in a direct way. But you could knock the door and ask your brother for that toys. This is called toy's closure ; your brother made it up for you, and he is now into outer scope .

Compare with a situation when a door was locked by draft and nobody inside (general function execution), and then some local fire occur and burn down the room (garbage collector:D), and then a new room was build and now you may leave another toys there (new function instance), but never get the same toys which were left in the first room instance.

For an advanced child I would put something like the following. It is not perfect, but it makes you feel about what it is:

 function playingInBrothersRoom (withToys) { // We closure toys which we played in the brother's room. When he come back and lock the door // your brother is supposed to be into the outer [[scope]] object now. Thanks god you could communicate with him. var closureToys = withToys || [], returnToy, countIt, toy; // Just another closure helpers, for brother's inner use. var brotherGivesToyBack = function (toy) { // New request. There is not yet closureToys on brother's hand yet. Give him a time. returnToy = null; if (toy && closureToys.length > 0) { // If we ask for a specific toy, the brother is going to search for it. for ( countIt = closureToys.length; countIt; countIt--) { if (closureToys[countIt - 1] == toy) { returnToy = 'Take your ' + closureToys.splice(countIt - 1, 1) + ', little boy!'; break; } } returnToy = returnToy || 'Hey, I could not find any ' + toy + ' here. Look for it in another room.'; } else if (closureToys.length > 0) { // Otherwise, just give back everything he has in the room. returnToy = 'Behold! ' + closureToys.join(', ') + '.'; closureToys = []; } else { returnToy = 'Hey, lil shrimp, I gave you everything!'; } console.log(returnToy); } return brotherGivesToyBack; } // You are playing in the house, including the brother's room. var toys = ['teddybear', 'car', 'jumpingrope'], askBrotherForClosuredToy = playingInBrothersRoom(toys); // The door is locked, and the brother came from the school. You could not cheat and take it out directly. console.log(askBrotherForClosuredToy.closureToys); // Undefined // But you could ask your brother politely, to give it back. askBrotherForClosuredToy('teddybear'); // Hooray, here it is, teddybear askBrotherForClosuredToy('ball'); // The brother would not be able to find it. askBrotherForClosuredToy(); // The brother gives you all the rest askBrotherForClosuredToy(); // Nothing left in there 

As you can see, the toys left in the room are still accessible via the brother and no matter if the room is locked. Here is a jsbin to play around with it.

An answer for a six-year-old (assuming he knows what a function is and what a variable is, and what data is):

Functions can return data. One kind of data you can return from a function is another function. When that new function gets returned, all the variables and arguments used in the function that created it don't go away. Instead, that parent function "closes." In other words, nothing can look inside of it and see the variables it used except for the function it returned. That new function has a special ability to look back inside the function that created it and see the data inside of it.

 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 

Another really simple way to explain it is in terms of scope:

Any time you create a smaller scope inside of a larger scope, the smaller scope will always be able to see what is in the larger scope.

Perhaps a little beyond all but the most precocious of six-year-olds, but a few examples that helped make the concept of closure in JavaScript click for me.

A closure is a function that has access to another function's scope (its variables and functions). The easiest way to create a closure is with a function within a function; the reason being that in JavaScript a function always has access to its containing function's scope.

 function outerFunction() { var outerVar = "monkey"; function innerFunction() { alert(outerVar); } innerFunction(); } outerFunction(); 

A function in JavaScript is not just a reference to a set of instructions (as in C language), but it also includes a hidden data structure which is composed of references to all nonlocal variables it uses (captured variables). Such two-piece functions are called closures. Every function in JavaScript can be considered a closure.

Closures are functions with a state. It is somewhat similar to "this" in the sense that "this" also provides state for a function but function and "this" are separate objects ("this" is just a fancy parameter, and the only way to bind it permanently to a function is to create a closure). While "this" and function always live separately, a function cannot be separated from its closure and the language provides no means to access captured variables.

Because all these external variables referenced by a lexically nested function are actually local variables in the chain of its lexically enclosing functions (global variables can be assumed to be local variables of some root function), and every single execution of a function creates new instances of its local variables, it follows that every execution of a function returning (or otherwise transferring it out, such as registering it as a callback) a nested function creates a new closure (with its own potentially unique set of referenced nonlocal variables which represent its execution context).

Also, it must be understood that local variables in JavaScript are created not on the stack frame, but on the heap and destroyed only when no one is referencing them. When a function returns, references to its local variables are decremented, but they can still be non-null if during the current execution they became part of a closure and are still referenced by its lexically nested functions (which can happen only if the references to these nested functions were returned or otherwise transferred to some external code).

一个例子:

 function foo (initValue) { //This variable is not destroyed when the foo function exits. //It is 'captured' by the two nested functions returned below. var value = initValue; //Note that the two returned functions are created right now. //If the foo function is called again, it will return //new functions referencing a different 'value' variable. return { getValue: function () { return value; }, setValue: function (newValue) { value = newValue; } } } function bar () { //foo sets its local variable 'value' to 5 and returns an object with //two functions still referencing that local variable var obj = foo(5); //Extracting functions just to show that no 'this' is involved here var getValue = obj.getValue; var setValue = obj.setValue; alert(getValue()); //Displays 5 setValue(10); alert(getValue()); //Displays 10 //At this point getValue and setValue functions are destroyed //(in reality they are destroyed at the next iteration of the garbage collector). //The local variable 'value' in the foo is no longer referenced by //anything and is destroyed too. } bar(); 

I'd simply point them to the Mozilla Closures page . It's the best, most concise and simple explanation of closure basics and practical usage that I've found. It is highly recommended to anyone learning JavaScript.

And yes, I'd even recommend it to a 6-year old — if the 6-year old is learning about closures, then it's logical they're ready to comprehend the concise and simple explanation provided in the article.