Вопрос

Я задал вопрос о приготовлении Карри, и были упомянуты замыкания.Что такое закрытие?Как это связано с приготовлением карри?

Это было полезно?

Решение

Область действия переменной

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

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), позволят вам сохранить ссылку на область (включая ее родительские области) даже после завершения выполнения блока, в котором были объявлены эти переменные, при условии, что вы где-то сохраните ссылку на этот блок или функцию.

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

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

Например

Вот действительно простой пример на 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 находится в пределах закрытия.

Другие советы

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

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

var x = makeCounter();

x(); returns 1

x(); returns 2

...etc...

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

Вот снова мой пример с карри:

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

var add3 = add(3);

add3(4); returns 7

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

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

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

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

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

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

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

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

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

Этот y требует определения, но это определение не является частью функции & # 8211; оно определено где-то еще, в его «окружающем контексте» (также известный как среда ). По крайней мере, это то, на что мы надеемся: 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;
   }

}

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

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

{
  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`]
}

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

Подробнее о теории здесь: https://stackoverflow.com/a/36878651/434562

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

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

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

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

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

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

(define x 3)

(define y 4)

(+ x y) returns 7

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

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

(define x 3)

(define y 4)

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

x returns 3

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

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

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

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

(define x 3)

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

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

Мы определяем x как 3 и плюс-x как его параметр, y, плюс значение x. Наконец, мы вызываем plus-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

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

Вот реальный пример того, почему 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 мс, запускается первый фрагмент и сохраняет переданные аргументы в его закрытии. Затем, через 5 секунд, когда происходит обратный вызов setTimeout , замыкание по-прежнему поддерживает эти переменные, поэтому оно может вызывать исходную функцию с исходными параметрами.
Это тип карри или функции украшения.

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

tl;dr

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

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

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

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

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

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

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)

Функции первого класса

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

В приведенном выше примере, startAt возвращает значение (Аноним) функция, которой присваивается функция closure1 и closure2.Итак, как вы видите, JavaScript обрабатывает функции точно так же, как и любые другие объекты (первоклассные граждане).

Привязка к имени

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

В приведенном выше примере:

  • В области видимости внутренней анонимной функции, y связан с 3.
  • В startAtсфера применения, x связан с 1 или 5 (в зависимости от закрытия).

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

Лексический охват

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

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

Есть два метода:

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

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

В приведенном выше примере мы можем видеть, что JavaScript имеет лексическую область действия, потому что когда x разрешен, привязка ищется в верхнем (startAt's) область видимости, основанная на исходном коде (анонимная функция, которая ищет x, определена внутри startAt) и не на основе стека вызовов, способа (области видимости, в которой) была вызвана функция.

Обертывание (крупный план)

В нашем примере, когда мы вызываем startAt, он вернет (первоклассную) функцию, которая будет назначена closure1 и closure2 таким образом, создается замыкание, поскольку переданные переменные 1 и 5 будут сохранены в течение startAtобласть видимости, которая будет заключена в возвращаемую анонимную функцию.Когда мы вызываем эту анонимную функцию через closure1 и closure2 с тем же аргументом (3), значение y будет найден немедленно (поскольку это параметр этой функции), но x не привязан к области действия анонимной функции, поэтому разрешение продолжается в (лексически) верхней области действия функции (которая была сохранена при закрытии), где x оказывается, что он связан либо с 1 или 5.Теперь мы знаем все для суммирования, так что результат может быть возвращен, а затем напечатан.

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

Приготовление карри

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

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

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

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
}

src: https://leanpub.com/javascriptallongesix/read#leanpub-auto-if-functions-without-free-variables-are-pure-are-closures-impure

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

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

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

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

foo = n_times(4)

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

foo.call(3)

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

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

.

Закрытие - это функция в 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, и это сумма его внутренней функции, ее собственной переменной, переменной внешней функции и значения глобальной переменной.

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

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 МОЖЕТ получить к нему доступ, точнее, копия, сохраненная вместе с функция как «повышение».

От Lua.org :

  

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

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

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

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

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

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.)-Начало%20Node.js-Apress%20(2014).pdf

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

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

Позвольте мне просто объяснить, когда созданная функция ничего не создает, пока она не вызовет цикл so for в 1-м коде, вызываемый 5 раз, но не вызываемый немедленно, поэтому, когда он вызывается, т. е. через 1 секунду, а также это асинхронно, поэтому перед завершением цикла for сохраните значение 5 в var i и, наконец, выполните 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);  

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

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

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

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

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

function init() {
    var name = “Mozilla”;
}

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top