Что такое "Закрытие"?

Я задал вопрос о Currying и закрытиях. Что такое закрытие? Как это относится к каррированию?

Ответы

Ответ 1

Переменная область

Когда вы объявляете локальную переменную, эта переменная имеет область видимости. Как правило, локальные переменные существуют только в блоке или функции, в которой вы их объявляете.

function() {
  var a = 1;
  console.log(a); // works
}    
console.log(a); // fails

Если я пытаюсь получить доступ к локальной переменной, большинство языков будет искать ее в текущей области, а затем через родительские области, пока они не достигнут корневой области.

var a = 1;
function() {
  console.log(a); // works
}    
console.log(a); // works

Когда с блоком или функцией завершается, его локальные переменные больше не нужны и обычно выбрасываются из памяти.

Так мы обычно ожидаем, что все будет работать.

Закрытие - это постоянная область видимости локальной переменной

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

Объект области видимости и все его локальные переменные связаны с функцией и будут сохраняться до тех пор, пока эта функция сохраняется.

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

Например

Вот действительно простой пример в JavaScript, который иллюстрирует это:

outer = function() {
  var a = 1;
  var inner = function() {
    console.log(a);
  }
  return inner; // this returns a function
}

var fnc = outer(); // execute outer to get inner 
fnc();

Здесь я определил функцию внутри функции. Внутренняя функция получает доступ ко всем локальным переменным внешней функции, включая a. Переменная a находится в области видимости для внутренней функции.

Обычно при выходе из функции все ее локальные переменные стираются. Однако, если мы возвращаем внутреннюю функцию и присваиваем ее переменной fnc чтобы она сохранялась после выхода из outer интерфейса, все переменные, которые находились в области видимости, когда был определен inner также сохраняются. Переменная a была закрыта - она находится в закрытии.

Обратите внимание, что переменная a полностью приватна для fnc. Это способ создания частных переменных в функциональном языке программирования, таком как JavaScript.

Как вы можете догадаться, когда я вызываю fnc() он печатает значение a, которое равно "1".

В языке без замыкания переменная a была бы собрана и отброшена при выходе из outer функции. Вызов fnc вызвал бы ошибку, потому a больше не существует.

В JavaScript переменная a сохраняется, поскольку область видимости переменной создается при первом объявлении функции и сохраняется до тех пор, пока функция продолжает существовать.

a относится к сфере outer. Область видимости inner имеет родительский указатель на область видимости outer. fnc - это переменная, которая указывает на inner. a сохраняется до тех пор, пока сохраняется fnc. a находится в закрытии.

Ответ 2

Я приведу пример (в JavaScript):

function makeCounter () {
  var count = 0;
  return function () {
    count += 1;
    return count;
  }
}

var x = makeCounter();

x(); returns 1

x(); returns 2

...etc...

Что делает эта функция makeCounter, она возвращает функцию, которую мы назвали x, которая будет подсчитывать по одному при каждом ее вызове. Поскольку мы не предоставляем никаких параметров х, он должен как-то помнить счет. Он знает, где его найти, исходя из того, что называется лексическим охватом - оно должно смотреть на то место, где оно определено, чтобы найти значение. Это "скрытое" значение - это то, что называется замыканием.

Вот мой пример currying:

function add (a) {
  return function (b) {
    return a + b;
  }
}

var add3 = add(3);

add3(4); returns 7

Что вы можете видеть, так это то, что при вызове add с параметром a (который равен 3) это значение содержится в закрытии возвращаемой функции, которую мы определяем как add3. Таким образом, когда мы вызываем add3, он знает, где найти значение для выполнения добавления.

Ответ 3

Ответ Кайла довольно хорош. Я думаю, что единственным дополнительным пояснением является то, что закрытие в основном представляет собой снимок стека в точке, где создается лямбда-функция. Затем, когда функция повторно выполняется, стек возвращается в это состояние перед выполнением функции. Таким образом, как отмечает Кайл, это скрытое значение (count) доступно, когда выполняется лямбда-функция.

Ответ 4

Прежде всего, вопреки тому, что говорит вам большинство людей, закрытие не является функцией! Так что это?
Это набор символов, определенных в функции "окружающий контекст" (известный как ее среда), которые делают его CLOSED-выражением (то есть выражением, в котором каждый символ определен и имеет значение, поэтому его можно оценить).

Например, когда у вас есть функция JavaScript:

function closed(x) {
  return x + 3;
}

это замкнутое выражение, потому что все символы, встречающиеся в нем, определены в нем (их значения понятны), поэтому вы можете его оценить. Другими словами, он является самодостаточным.

Но если у вас есть такая функция:

function open(x) {
  return x*y + 3;
}

это открытое выражение, потому что в нем есть символы, которые в нем не определены. А именно, y. Рассматривая эту функцию, мы не можем сказать, что такое y и что это значит, мы не знаем ее значения, поэтому мы не можем оценить это выражение. То есть мы не можем назвать эту функцию, пока не скажем, что означает y. Этот y называется свободной переменной.

Этот y требует определения, но это определение не является частью функции - оно определяется где-то еще, в его "окружающем контексте" (также известном как среда). По крайней мере, на что мы надеемся: P

Например, он может быть определен глобально:

var y = 7;

function open(x) {
  return x*y + 3;
}

Или это можно определить в функции, которая его обертывает:

var global = 2;

function wrapper(y) {
   var w = "unused";

   return function(x) {
     return x*y + 3;
   }

}

Часть среды, которая дает свободным переменным в выражении их значения, является замыканием. Он называется так, потому что он превращает открытое выражение в замкнутое, предоставляя эти отсутствующие определения для всех его свободных переменных, чтобы мы могли его оценить.

В приведенном выше примере внутренняя функция (которую мы не дали имени, потому что она нам не нужна) является открытым выражением, поскольку переменная y в ней свободна - ее определение не входит в функцию, в функции, которая его обертывает. Среда для этой анонимной функции представляет собой набор переменных:

{
  global: 2,
  w: "unused",
  y: [whatever has been passed to that wrapper function as its parameter `y`]
}

Теперь закрытие является той частью этой среды, которая закрывает внутреннюю функцию, предоставляя определения для всех ее свободных переменных. В нашем случае единственной свободной переменной во внутренней функции было y, поэтому закрытие этой функции является этим подмножеством своей среды:

{
  y: [whatever has been passed to that wrapper function as its parameter `y`]
}

Два других символа, определенные в среде, не являются частью закрытия этой функции, потому что она не требует их запуска. Они не нужны, чтобы закрыть его.

Подробнее об этой теории здесь: fooobar.com/questions/4901/...

Стоит отметить, что в приведенном выше примере функция-обертка возвращает свою внутреннюю функцию как значение. Момент, который мы называем этой функцией, может быть удален во времени с момента, когда функция была определена (или создана). В частности, его функция обертки больше не работает, а ее параметры, которые были в стеке вызовов, больше не существуют: P Это создает проблему, потому что внутренняя функция нуждается в y, чтобы быть там, когда она вызывается! Другими словами, для того, чтобы как-то пережить функцию обертки, необходимо, чтобы переменные были закрыты, и там, где это необходимо. Поэтому внутренняя функция должна сделать моментальный снимок этих переменных, которые делают его закрытие и сохраняют их где-то в безопасности для последующего использования. (Где-то вне стека вызовов.)

И поэтому люди часто путают термин закрытие как особый тип функции, который может делать такие снимки внешних переменных, которые они используют, или структуру данных, используемую для хранения этих переменных позже. Но я надеюсь, что теперь вы понимаете, что они не являются самим закрытием - это просто способы реализовать замыкания на языке программирования или языковые механизмы, позволяющие при необходимости заменять переменные из функции закрытия. Там много неправильных представлений о закрытии, которые (излишне) делают эту тему более запутанной и сложной, чем она есть на самом деле.

Ответ 5

Закрытие - это функция, которая может ссылаться на состояние в другой функции. Например, в Python это использует закрытие "inner":

def outer (a):
    b = "variable in outer()"
    def inner (c):
        print a, b, c
    return inner

# Now the return value from outer() can be saved for later
func = outer ("test")
func (1) # prints "test variable in outer() 1

Ответ 6

Чтобы облегчить понимание закрытий, было бы полезно изучить, как они могут быть реализованы на процедурном языке. Это объяснение будет следовать упрощенной реализации замыканий на Схеме.

Чтобы начать, я должен ввести понятие пространства имен. Когда вы вводите команду в интерпретатор Схемы, она должна оценивать различные символы в выражении и получать их значение. Пример:

(define x 3)

(define y 4)

(+ x y) returns 7

Определяющие выражения сохраняют значение 3 в пятне для x и значение 4 в пятне для y. Затем, когда мы вызываем (+ x y), интерпретатор просматривает значения в пространстве имен и может выполнять операцию и возвращать 7.

Однако на Схеме есть выражения, которые позволяют временно переопределить значение символа. Вот пример:

(define x 3)

(define y 4)

(let ((x 5))
   (+ x y)) returns 9

x returns 3

То, что делает ключевое слово let, представляет новое пространство имен с x как значение 5. Вы заметите, что он все еще может видеть, что y равно 4, что возвращает сумму, равную 9. Вы также можете увидеть, что после выражения закончил x вернулся к состоянию 3. В этом смысле x временно маскируется локальным значением.

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

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

Теперь перейдем к реализации первоклассных функций на данный момент. Более или менее, функция представляет собой набор команд для выполнения, когда функция называется кульминацией в возвращаемом значении. Когда мы читаем функцию, мы можем хранить эти инструкции за кулисами и запускать их при вызове функции.

(define x 3)

(define (plus-x y)
  (+ x y))

(let ((x 5))
  (plus-x 4)) returns ?

Определим x как 3, а плюс-x - его параметр, y, плюс значение x. Наконец, мы называем плюс-x в среде, где x был замаскирован новым x, этот оценивается 5. Если мы просто сохраняем операцию (+ xy) для функции plus-x, поскольку мы находимся в контексте из x будет 5, результат будет равен 9. Это то, что называется динамическим охватом.

Однако, Scheme, Common Lisp и многие другие языки имеют то, что называется лексическим охватом - помимо хранения операции (+ x y) мы также сохраняем пространство имен в этой конкретной точке. Таким образом, когда мы просматриваем значения, мы можем видеть, что x в этом контексте действительно 3. Это замыкание.

(define x 3)

(define (plus-x y)
  (+ x y))

(let ((x 5))
  (plus-x 4)) returns 7

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

Ответ 7

Вот пример реального мира, почему Closures подталкивает задницу... Это прямо из моего кода Javascript. Позвольте мне проиллюстрировать.

Function.prototype.delay = function(ms /*[, arg...]*/) {
  var fn = this,
      args = Array.prototype.slice.call(arguments, 1);

  return window.setTimeout(function() {
      return fn.apply(fn, args);
  }, ms);
};

И вот как вы его используете:

var startPlayback = function(track) {
  Player.play(track);  
};
startPlayback(someTrack);

Теперь представьте, что вы хотите, чтобы воспроизведение запустилось, например, через 5 секунд после этого фрагмента кода. Хорошо, что легко с delay и это закрытие:

startPlayback.delay(5000, someTrack);
// Keep going, do other things

Когда вы вызываете delay с 5000 ms, первый фрагмент запускается и сохраняет переданные аргументы в его закрытии. Затем через 5 секунд, когда происходит обратный вызов setTimeout, закрытие все еще сохраняет эти переменные, поэтому оно может вызывать исходную функцию с исходными параметрами.
Это тип currying или функция украшения.

Без замыканий вам придется каким-то образом поддерживать эти переменные за пределами функции, таким образом забивая код вне функции чем-то, что логически принадлежит внутри него. Использование закрытий может значительно улучшить качество и читаемость вашего кода.

Ответ 8

ТЛ; др

Замыкание - это функция, и ее область действия назначается (или используется как) переменной. Таким образом, закрытие имени: область действия и функция заключены и используются так же, как и любая другая сущность.

Подробное объяснение стиля Википедии

Согласно Википедии, закрытие:

Методы реализации привязки лексически ограниченных имен в языках с первоклассными функциями.

Что это значит? Давайте посмотрим на некоторые определения.

Я объясню замыкания и другие связанные определения, используя этот пример:

function startAt(x) {
    return function (y) {
        return x + y;
    }
}

var closure1 = startAt(1);
var closure2 = startAt(5);

console.log(closure1(3)); // 4 (x == 1, y == 3)
console.log(closure2(3)); // 8 (x == 5, y == 3)

Ответ 9

Функции, не содержащие свободных переменных, называются чистыми функциями.

Функции, содержащие одну или несколько свободных переменных, называются замыканиями.

var pure = function pure(x){
  return x 
  // only own environment is used
}

var foo = "bar"

var closure = function closure(){
  return foo 
  // foo is a free variable from the outer environment
}

источник: https://leanpub.com/javascriptallongesix/read#leanpub-auto-if-functions-without-free-variables-are-pure-are-closures-impure

Ответ 10

В нормальной ситуации переменные связаны по правилу определения области видимости: локальные переменные работают только внутри определенной функции. Закрытие - это способ временного нарушения этого правила для удобства.

def n_times(a_thing)
  return lambda{|n| a_thing * n}
end

в приведенном выше коде, lambda(|n| a_thing * n} является закрытием, потому что a_thing передается лямбдой (анонимным создателем функции).

Теперь, если вы поместите полученную анонимную функцию в функциональную переменную.

foo = n_times(4)

foo нарушит нормальное правило видимости и начнет использовать 4 внутри.

foo.call(3)

возвращает 12.

Ответ 11

Короче говоря, указатель на функцию - это просто указатель на местоположение в базе кода программы (например, счетчик программ). В то время как Closure = указатель на функцию + фрейм стека.

.

Ответ 12

Закрытие - это функция в JavaScript, где функция имеет доступ к своим собственным переменным области видимости, доступ к внешним переменным функции и доступ к глобальным переменным.

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

Внутренняя функция может обращаться к переменным, определенным в ее собственной области видимости, области внешних функций и глобальной области видимости. А внешняя функция может обращаться к переменной, определенной в ее собственной области видимости и глобальной области видимости.

******************
Example of Closure
******************

var globalValue = 5;

function functOuter() 
{
    var outerFunctionValue = 10;

    //Inner function has access to the outer function value
    //and the global variables
    function functInner() 
    {
        var innerFunctionValue = 5;
        alert(globalValue+outerFunctionValue + innerFunctionValue);
    }
    functInner();
}
functOuter();

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

Ответ 13

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

local old_dofile = dofile

function dofile( filename )
  if filename == nil then
    error( 'Can not use default of stdin.' )
  end

  old_dofile( filename )
end

Значение old_dofile исчезает, когда этот блок кода заканчивает его область видимости (потому что он локальный), однако это значение было заключено в закрытие, поэтому новая переопределенная функция dofile может получить к ней доступ, или, скорее, копию, сохраненную вместе с как "upvalue".

Ответ 14

Из Lua.org:

Когда функция записывается в другую функцию, она имеет полный доступ к локальным переменным из закрывающей функции; эта функция называется лексическим охватом. Хотя это может показаться очевидным, это не так. Лексическая область обзора, плюс первоклассные функции, является мощной концепцией на языке программирования, но несколько языков поддерживают эту концепцию.

Ответ 15

Если вы находитесь в мире Java, вы можете сравнить замыкание с функцией-членом класса. Посмотрите на этот пример

var f=function(){
  var a=7;
  var g=function(){
    return a;
  }
  return g;
}

Функция g является замыканием: g закрывает a in. Таким образом, g можно сравнить с функцией-членом, a можно сравнить с полем класса, а функция f с классом.

Ответ 16

Затворы Всякий раз, когда у нас есть функция, определенная внутри другой функции, внутренняя функция имеет доступ к объявленным переменным во внешней функции. Ключи лучше всего объясняются примерами. В листинге 2-18 вы можете видеть, что внутренняя функция имеет доступ к переменной (variableInOuterFunction) из внешний scope. Переменные во внешней функции были закрыты (или связаны) внутренней функцией. Следовательно, термин закрытие. Понятие само по себе достаточно просто и достаточно интуитивно.

Listing 2-18:
    function outerFunction(arg) {
     var variableInOuterFunction = arg;

     function bar() {
             console.log(variableInOuterFunction); // Access a variable from the outer scope
     }
     // Call the local function to demonstrate that it has access to arg
     bar(); 
    }
    outerFunction('hello closure!'); // logs hello closure!

источник: http://index-of.es/Varios/Basarat%20Ali%20Syed%20(auth.)-Beginning%20Node.js-Apress%20(2014).pdf

Ответ 17

Пожалуйста, посмотрите код ниже, чтобы понять замыкание более глубоко:

        for(var i=0; i< 5; i++){            
            setTimeout(function(){
                console.log(i);
            }, 1000);                        
        }

Вот что будет выходной? 0,1,2,3,4 не то что будет 5,5,5,5,5 из-за закрытия

Так как это решит? Ответ ниже:

       for(var i=0; i< 5; i++){
           (function(j){     //using IIFE           
                setTimeout(function(){
                               console.log(j);
                           },1000);
            })(i);          
        }

Позвольте мне просто объяснить, что когда созданная функция ничего не происходит, пока она не вызовет цикл for в 1-м коде, который вызывается 5 раз, но не вызывается сразу, поэтому, когда он вызывается, т.е. Через 1 секунду, а также это происходит асинхронно, так что до этого цикл завершается и сохраняется значение 5. в var я и, наконец, выполнить функцию setTimeout пять раз и вывести 5,5,5,5,5

Вот как это решить, используя IIFE, т.е. выражение функции немедленного вызова

       (function(j){  //i is passed here           
            setTimeout(function(){
                           console.log(j);
                       },1000);
        })(i);  //look here it called immediate that is store i=0 for 1st loop, i=1 for 2nd loop, and so on and print 0,1,2,3,4

Для получения дополнительной информации, пожалуйста, поймите контекст выполнения, чтобы понять замыкание.

  • Есть еще одно решение для решения этой проблемы с помощью let (функция ES6), но под капотом работает вышеуказанная функция

     for(let i=0; i< 5; i++){           
         setTimeout(function(){
                        console.log(i);
                    },1000);                        
     }
    
    Output: 0,1,2,3,4
    

=> Больше объяснений:

В памяти, когда для цикла выполнения изображения сделать, как показано ниже:

Петля 1)

     setTimeout(function(){
                    console.log(i);
                },1000);  

Петля 2)

     setTimeout(function(){
                    console.log(i);
                },1000); 

Петля 3)

     setTimeout(function(){
                    console.log(i);
                },1000); 

Петля 4)

     setTimeout(function(){
                    console.log(i);
                },1000); 

Петля 5)

     setTimeout(function(){
                    console.log(i);
                },1000);  

Здесь я не выполняется, а затем после завершения цикла var я сохраняет значение 5 в памяти, но его область видимости всегда видна в его 5,5,5,5,5 функции, поэтому, когда функция выполняется внутри setTimeout пять раз, она печатает 5,5,5,5,5

поэтому, чтобы решить эту проблему, используйте IIFE, как описано выше.

Ответ 18

Curry: позволяет частично оценить функцию, передав только подмножество ее аргументов. Учти это:

function multiply (x, y) {
  return x * y;
}

const double = multiply.bind(null, 2);

const eight = double(4);

eight == 8;

Закрытие: Закрытие - это не что иное, как доступ к переменной за пределами области действия функции. Важно помнить, что функция внутри функции или вложенная функция не является замыканием. Замыкания всегда используются, когда необходимо получить доступ к переменным вне области действия функции.

function apple(x){
   function google(y,z) {
    console.log(x*y);
   }
   google(7,2);
}

apple(3);

// the answer here will be 21

Ответ 19

Закрытие очень просто. Мы можем рассмотреть это следующим образом: Закрытие = функция + его лексическое окружение

Рассмотрим следующую функцию:

function init() {
    var name = 'Mozilla';
}

Каким будет закрытие в вышеуказанном случае? Функция init() и переменные в ее лексической среде, т.е. имя. Закрытие= init() + имя

Рассмотрим другую функцию:

function init() {
    var name = 'Mozilla';
    function displayName(){
        alert(name);
}
displayName();
}

Какие здесь будут закрытия? Внутренняя функция может обращаться к переменным внешней функции. displayName() может получить доступ к имени переменной, объявленной в родительской функции init(). Однако те же локальные переменные в displayName() будут использоваться, если они существуют.

Закрытие 1: функция инициализации + (имя переменной + функция displayName()) → лексическая область действия

Закрытие 2: функция displayName + (имя переменной) → лексическая область

Ответ 20

Закрытия предоставляют JavaScript с состоянием.

Государство в программировании просто означает запоминание вещей.

Пример

var a = 0;

a = a + 1; // => 1
a = a + 1; // => 2
a = a + 1; // => 3

В приведенном выше случае состояние сохраняется в переменной "a". Мы добавляем 1 к "a" несколько раз. Мы можем сделать это только потому, что можем "запомнить" значение. Держатель состояния "а" хранит это значение в памяти.

Зачастую на языках программирования вы хотите отслеживать вещи, запоминать информацию и получать к ней доступ позже.

Это, на других языках, обычно достигается с помощью классов. Класс, как и переменные, отслеживает свое состояние. И экземпляры этого класса, в свою очередь, также имеют внутри себя состояние. Состояние просто означает информацию, которую вы можете сохранить и получить позже.

Пример

class Bread {
  constructor (weight) {
    this.weight = weight;
  }

  render () {
    return 'My weight is ${this.weight}!';
  }
}

Как мы можем получить доступ к "weight" из метода "render"? Ну, спасибо государству. Каждый экземпляр класса Bread может отображать свой собственный вес, читая его из "состояния", места в памяти, где мы могли бы хранить эту информацию.

Теперь JavaScript - это очень уникальный язык, который исторически не имеет классов (сейчас он есть, но под капотом есть только функции и переменные), поэтому Closures предоставляют способ JavaScript для запоминания вещей и доступа к ним позже.

Пример

var n = 0;
var count = function () {
  n = n + 1;
  return n;
};

count(); // # 1
count(); // # 2
count(); // # 3

В приведенном выше примере достигнута цель "сохранить состояние" с помощью переменной. Это здорово! Однако это имеет тот недостаток, что переменная (держатель "состояния") теперь доступна. Мы можем сделать лучше. Мы можем использовать замыкания.

Пример

var countGenerator = function () {
  var n = 0;
  var count = function () {
    n = n + 1;
    return n;
  };

  return count;
};

var count = countGenerator();
count(); // # 1
count(); // # 2
count(); // # 3

Это фантастика.

Теперь наша функция "считать" может считать. Он может сделать это только потому, что может "удерживать" состояние. Состояние в этом случае - переменная "n". Эта переменная сейчас закрыта. Закрыто во времени и пространстве. со временем, потому что вы никогда не сможете восстановить его, изменить его, присвоить ему значение или напрямую взаимодействовать с ним. В космосе, потому что он географически вложен в функцию countGenerator.

Почему это фантастика? Потому что без привлечения какого-либо другого сложного и сложного инструмента (например, классов, методов, экземпляров и т.д.) Мы можем 1. скрыть 2. управление на расстоянии

Мы скрываем состояние, переменную "n", что делает ее закрытой! Мы также создали API, который может управлять этой переменной заданным способом. В частности, мы можем назвать API, например, "count()", и это добавляет 1 к "n" с "расстояния". Никто, ни кто-либо другой, не сможет получить доступ к "n", кроме как через API.

JavaScript действительно удивителен своей простотой.

Закрытия являются большой частью того, почему это так.

Ответ 21

Простой пример в Groovy для вашей справки:

def outer() {
    def x = 1
    return { -> println(x)} // inner
}
def innerObj = outer()
innerObj() // prints 1