Как работают блокировки JavaScript?



Answers

Всякий раз, когда вы видите ключевое слово 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 который был определен как аргумент foo , и он также может получить доступ к tmp из foo .

Это закрытие. Функция не должна возвращаться , чтобы называться замыканием. Простое обращение к переменным за пределами вашей непосредственной лексической области создает закрытие .

function foo(x) {
  var tmp = 3;

  return function (y) {
    console.log(x + y + (++tmp)); // will also log 16
  }
}

var bar = foo(2); // bar is now a closure.
bar(10);

Вышеупомянутая функция также будет записывать 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();

Когда вызывается функция JavaScript, создается новый контекст выполнения. Вместе с аргументами функции и родительским объектом этот контекст выполнения также принимает все переменные, объявленные вне него (в приведенном выше примере оба «a» и «b»).

Можно создать более чем одну функцию закрытия, либо путем возврата их списка, либо путем установки их на глобальные переменные. Все они будут относиться к одному и тому же x и тому же tmp , они не создают свои собственные копии.

Здесь число x является литеральным числом. Как и в других литералах в JavaScript, когда вызывается foo , число x копируется в foo как его аргумент x .

С другой стороны, JavaScript всегда использует ссылки при работе с объектами. Если, скажем, вы вызвали foo с объектом, закрытие, которое он возвращает, будет ссылаться на этот оригинальный объект!

function foo(x) {
  var tmp = 3;

  return function (y) {
    console.log(x + y + tmp);
    x.memb = x.memb ? x.memb + 1 : 1;
    console.log(x.memb);
  }
}

var age = new Number(2);
var bar = foo(age); // bar is now a closure referencing age.
bar(10);

Как и ожидалось, каждый вызов bar(10) будет увеличивать x.memb . Нельзя ожидать, что x просто ссылается на тот же объект, что и age переменная! После пары звонков в bar age.memb будет 2! Эта ссылка служит основой для утечек памяти с объектами HTML.

Question

Как бы вы объяснили закрытие JavaScript для кого-то, у кого есть знания о концепциях, из которых они состоят (например, функции, переменные и т. П.), Но не понимают самих замыканий?

Я видел пример схемы, приведенный в Википедии, но, к сожалению, это не помогло.




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.




Замки трудно объяснить, потому что они используются, чтобы сделать какую-то поведенческую работу, которую все интуитивно ожидают в любом случае. Я нахожу лучший способ объяснить их (и то, как я узнал, что они делают) - представить ситуацию без них:

    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.




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.




Принимая этот вопрос всерьез, мы должны выяснить, что типичный 6-летний человек способен когнитивно, хотя, по общему признанию, тот, кто интересуется JavaScript, не так типичен.

О развитии детства: от 5 до 7 лет говорится:

Ваш ребенок сможет следовать двухэтапным направлениям. Например, если вы скажете своему ребенку: «Идите на кухню и возьмите мешок для мусора», они смогут запомнить это направление.

Мы можем использовать этот пример для объяснения замыканий следующим образом:

Кухня - это закрытие, в котором есть локальная переменная, называемая trashBags . Внутри кухни есть функция getTrashBag которая получает один мешок для мусора и возвращает его.

Мы можем кодировать это в 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() , создается новое закрытие со своими отдельными trashBags .
  • Переменная trashBags является локальной для каждой кухни и недоступна снаружи, но внутренняя функция свойства getTrashBag имеет к ней доступ.
  • Каждый вызов функции создает замыкание, но нет необходимости держать замыкание, если внутренняя функция, которая имеет доступ к внутренней части замыкания, может быть вызвана из-за закрытия. Возвращение объекта с getTrashBag функции getTrashBag делает это здесь.



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.




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.




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



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. That's it. 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");



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

ALERT: monkey

In the above example, outerFunction is called which in turn calls innerFunction. Note how outerVar is available to innerFunction, evidenced by its correctly alerting the value of outerVar.

Now consider the following:

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

var referenceToInnerFunction = outerFunction();
alert(referenceToInnerFunction());

ALERT: monkey

referenceToInnerFunction is set to outerFunction(), which simply returns a reference to innerFunction. When referenceToInnerFunction is called, it returns outerVar. Again, as above, this demonstrates that innerFunction has access to outerVar, a variable of outerFunction. Furthermore, it is interesting to note that it retains this access even after outerFunction has finished executing.

And here is where things get really interesting. If we were to get rid of outerFunction, say set it to null, you might think that referenceToInnerFunction would loose its access to the value of outerVar. But this is not the case.

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

var referenceToInnerFunction = outerFunction();
alert(referenceToInnerFunction());

outerFunction = null;
alert(referenceToInnerFunction());

ALERT: monkey ALERT: monkey

But how is this so? How can referenceToInnerFunction still know the value of outerVar now that outerFunction has been set to null?

The reason that referenceToInnerFunction can still access the value of outerVar is because when the closure was first created by placing innerFunction inside of outerFunction, innerFunction added a reference to outerFunction's scope (its variables and functions) to its scope chain. What this means is that innerFunction has a pointer or reference to all of outerFunction's variables, including outerVar. So even when outerFunction has finished executing, or even if it is deleted or set to null, the variables in its scope, like outerVar, stick around in memory because of the outstanding reference to them on the part of the innerFunction that has been returned to referenceToInnerFunction. To truly release outerVar and the rest of outerFunction's variables from memory you would have to get rid of this outstanding reference to them, say by setting referenceToInnerFunction to null as well.

//////////

Two other things about closures to note. First, the closure will always have access to the last values of its containing function.

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

    innerFunction();
}

outerFunction();

ALERT: gorilla

Second, when a closure is created, it retains a reference to all of its enclosing function's variables and functions; it doesn't get to pick and choose. And but so, closures should be used sparingly, or at least carefully, as they can be memory intensive; a lot of variables can be kept in memory long after a containing function has finished executing.




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?




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.




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.

Result

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




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



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.






Links