Одно всеобъемлющее определение закрытия JavaScript

Я прочитал 10 ссылок SO на закрытие, ссылки MDN и другие статьи в блогах. Кажется, что все они определяют замыкания по-своему. Например, из документации MDN:

function makeFunc() {
  var name = "Mozilla";
  function displayName() {
    alert(name);
  }
  return displayName;
}

var myFunc = makeFunc();
myFunc();

И вот их объяснение закрытия:

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

Решение этой загадки в том, что myFunc превратился в закрытие. Замыкание - это особый вид объекта, который объединяет две вещи: функцию и среду, в которой эта функция была создана. Среда состоит из любых локальных переменных, которые были в области видимости во время создания замыкания. В этом случае myFunc - это замыкание, которое включает в себя как функцию displayName, так и строку Mozilla, существовавшую при создании замыкания.

Это сообщение ниже StackOverflow отвечает на закрытие как стек видимых областей. Какие типы областей видимости существуют в Javascript?

Где я запутался: закрытие объекта? Или это просто аномальная ситуация с областью видимости, когда внутренняя вложенная функция имеет доступ к переменной, определенной вне себя, но локальной по отношению к родительской функции контейнера, даже после того, как родительская функция уже выполнена? Является ли закрытие объектом, относящимся к этой ситуации вложенной функции (области действия), например myFunc, или это сама внутренняя функция?


person Athapali    schedule 29.01.2015    source источник
comment
Я склонен закрыть этот вопрос как дубликат. Однако, похоже, вы провели некоторое исследование. Возможно, этот вопрос и ответ помогут развеять ваши сомнения: stackoverflow.com/q/12930272/783743   -  person Aadit M Shah    schedule 29.01.2015
comment
@AaditMShah Большое спасибо! Я прочитал ваши ответы по закрытию и анализу, и они потрясающие !! Спасибо, что нашли время ответить на эти вопросы для таких запутанных людей, как я !!   -  person Athapali    schedule 29.01.2015
comment
Вы также прочитали Как работают замыкания JavaScript?   -  person Bergi    schedule 29.01.2015
comment
Одно определение? закрытие - это функция [объект] со ссылкой на область видимости. в котором ищутся его свободные переменные. В строгом смысле мы используем этот термин только для функций, в которых эти свободные переменные не являются глобальными.   -  person Bergi    schedule 29.01.2015


Ответы (3)


Короче говоря,

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

Больше контекста:

var v1; // I'm accessible anywhere    
function a() {
    var v2;
    function b() { // I can access v2 and v1
        var v3;
        function c() {  // I can access v1, v2, v3
            var v4;
        }
        return c;
    }
    return b();
}
var f = a();

В приведенном выше примере a, b, c все являются замыканиями, у которых есть доступ к их соответствующей родительской области, и это продолжается рекурсивно до window или глобального контекста.


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

person Amit Joki    schedule 29.01.2015
comment
Сколько замыканий определено в примере, приведенном в этом посте? stackoverflow.com / questions / 12543395 /. Это одно закрытие или 5 закрытий? - person Athapali; 29.01.2015
comment
@SariksaThapa Технически каждая функция в JavaScript является закрытием, потому что каждая функция в JavaScript несет с собой свой лексический контекст. Однако замыкания интересны только тогда, когда значения, которые они закрывают, выходят за рамки (что делает закрытие заметным). - person Aadit M Shah; 29.01.2015
comment
++ но прекратите редактировать! ваш ответ становится все менее емким! :-D Отличная финальная точка, кстати. - person G. Cito; 29.01.2015

Вы можете думать о функции JS как о такой структуре:

class Function : Object {
  bytes      bytecode;
  varframe   varsAndArgs;
}

class varframe{
  array<value>  values;
  ptr<varframe> parent;
}

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

Итак, когда вы определяете

function makeFunc() {
  var name = "Mozilla";
  function displayName() {
    alert(name);
  }
  return displayName;
}

этот displayName (const / variable) будет содержать экземпляр класса Function, который будет содержать ссылку на его собственный varframe этой структуры:

varframe(displayName) 
  values[0] // empty array, no variables in it
  parent -> varframe(makeFunc) 
              values[1] // one variable "name" at index 0;
              parent = null    

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

person c-smile    schedule 29.01.2015

В прошлом многие материалы курса и ссылки подчеркивали объектно-ориентированные аспекты JavaScript, иногда игнорируя функциональные подходы. Я думаю, что это начало меняться с развитием фреймворков и обширных коллекций JS-библиотек. Secrets of the JavaScript Ninja утверждает, что овладение функциями является фундаментальной частью эффективного использования JavaScript. В Ninja определение закрытия является более общим:

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

                                         -- "Chapter 5: Closing in on closures"

Обсуждая закрытие, Эффективный JavaScript ставит (более или менее ) Сюда:

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

Исходный код для главы 2 «Эффективный JavaScript». Пункт 11 «Как освоиться с замыканиями» можно найти на gibhub по адресу:

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

person G. Cito    schedule 29.01.2015
comment
может ссылаться на переменные, возвращаемые другой функцией для меня звучит неправильно. Функция не может вернуть переменную. - person Bergi; 29.01.2015
comment
изменил его ... функция - это объект, который может иметь набор определенных свойств, а закрытие может хранить ссылки на них ... - person G. Cito; 29.01.2015