Замыкания в JavaScript

    Если вы используете JavaScript, но при этом так до конца и не разобрались, что же это за чудная штука такая — замыкания, и зачем она нужна — эта статья для вас.

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

    Если вы объявляете функцию внутри другой функции, первая получает доступ к переменным и аргументам последней:
    function outerFn(myArg) {
       var myVar;
       function innerFn() {
          //имеет доступ к myVar и myArg
       }
    }
    При этом, такие переменные продолжают существовать и остаются доступными внутренней функцией даже после того, как внешняя функция, в которой они определены, была исполнена.

    Рассмотрим пример — функцию, возвращающую кол-во собственных вызовов:
    function createCounter() {
       var numberOfCalls = 0;
       return function() {
          return ++numberOfCalls;
       }
    }
    var fn = createCounter();
    fn(); //1
    fn(); //2
    fn(); //3
    В данном примере функция, возвращаемая createCounter, использует переменную numberOfCalls, которая сохраняет нужное значение между ее вызовами (вместо того, чтобы сразу прекратить своё существование с возвратом createCounter).

    Именно за эти свойства такие «вложенные» функции в JavaScript называют замыканиями (термином, пришедшим из функциональных языков программирования) — они «замыкают» на себя переменные и аргументы функции, внутри которой определены.

    Применение замыканий


    Упростим немножко пример выше — уберём необходимость отдельно вызывать функцию createCounter, сделав ее аномимной и вызвав сразу же после ее объявления:
    var fn = (function() {
       var numberOfCalls = 0;
       return function() {
          return ++ numberOfCalls;
       }
    })();
    Такая конструкция позволила нам привязать к функции данные, сохраняющиеся между ее вызовами — это одно из применений замыканий. Иными словами, с помощью них мы можем создавать функции, имеющие своё изменяемое состояние.

    Другое хорошее применение замыканий — создание функций, в свою очередь тоже создающих функции — то, что некоторые назвали бы приёмом т.н. метапрограммирования. Например:
    var createHelloFunction = function(name) {
       return function() {
          alert('Hello, ' + name);
       }
    }
    var sayHelloHabrahabr = createHelloFunction('Habrahabr');
    sayHelloHabrahabr(); //alerts «Hello, Habrahabr»
    Благодаря замыканию возвращаемая функция «запоминает» параметры, переданные функции создающей, что нам и нужно для подобного рода вещей.

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

    Рассмотрим чуть более сложный пример — метод, привязывающий функцию к определённому контексту (т.е. объекту, на который в ней будет указывать слово this).
    Function.prototype.bind = function(context) {
       var fn = this;
       return function() {
          return fn.apply(context, arguments);
       };
    }
    var HelloPage = {
       name: 'Habrahabr',
       init: function() {
          alert('Hello, ' + this.name);
       }
    }
    //window.onload = HelloPage.init; //алертнул бы undefined, т.к. this указывало бы на window
    window.onload = HelloPage.init.bind(HelloPage); //вот теперь всё работает
    В этом примере с помощью замыканий функция, вощвращаемая bind'ом, запоминает в себе начальную функцию и присваиваемый ей контекст.

    Следующее, принципиально иное применение замыканий — защита данных (инкапсуляция). Рассмотрим следующую конструкцию:
    (function() {
       …
    })();
    Очевидно, внутри замыкания мы имеем доступ ко всем внешним данным, но при этом оно имеет и собственные. Благодаря этому мы можем окружать части кода подобной конструкцией с целью закрыть попавшие внутрь локальные переменные от доступа снаружи. (Один из примеров ее использования вы можете увидеть в исходном коде библиотеки jQuery, которая окружает замыканием весь свой код, чтобы не выводить за его пределы нужные только ей переменные).

    Есть, правда, одна связанная с таким применением ловушка — внутри замыкания теряется значение слова this за его пределами. Решается она следующим образом:
    (function() {
       //вышестоящее this сохранится
    }).call(this);

    Рассмотрим еще один приём из той же серии. Повсеместно популяризовали его разработчики фреймворка Yahoo UI, назвав его «Module Pattern» и написав о нём целую статью в официальном блоге.

    Пускай у нас есть объект (синглтон), содержащий какие-либо методы и свойства:
    var MyModule = {
       name: 'Habrahabr',
       sayPreved: function(name) {
          alert('PREVED ' + name.toUpperCase())
       },   
       sayPrevedToHabrahabr: function() {
          this.sayPreved(this.name);
       }
    }
    MyModule.sayPrevedToHabrahabr();
    С помощью замыкания мы можем сделать методы и свойства, которые вне объекта не используютя, приватными (т.е. доступными только ему):
    var MyModule = (function() {
       var name = 'Habrahabr';
       function sayPreved() {
          alert('PREVED ' + name.toUpperCase());
       }
       return {
          sayPrevedToHabrahabr: function() {
             sayPreved(name);
          }
       }
    })();
    MyModule.sayPrevedToHabrahabr(); //alerts «PREVED Habrahabr»

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

    Пускай у нас есть массив ссылок, и наша задача — сделать так, чтобы при клике на каждую выводился алертом ее порядковый номер. Первое решение, что приходит в голову, выглядит так:
    for (var i = 0; i < links.length; i++) {
       links[i].onclick = function() {
          alert(i);
       }
    }
    На деле же оказывается, что при клике на любую ссылку выводится одно и то же число — значение links.length. Почему так происходит? В связи с замыканием объявленная вспомогательная переменная i продолжает существовать, при чём и в тот момент, когда мы кликаем по ссылке. Поскольку к тому времени цикл уже прошёл, i остаётся равным кол-ву ссылок — это значение мы и видим при кликах.

    Решается эта проблема следующим образом:
    for (var i = 0; i < links.length; i++) {
       (function(i) {
          links[i].onclick = function() {
             alert(i);
          }
       })(i);
    }
    Здесь с помощью еще одного замыкания мы «затеняем» переменную i, создавая ее копию в его локальной области видимости на каждом шаге цикла. Благодаря этому всё теперь работает как задумывалось.

    Вот и всё. Эта статья, конечно, не претендует на звание исчерпывающей, но кому-нибудь, надеюсь, всё-таки поможет разобраться. Спасибо за внимание!
    Поделиться публикацией
    Комментарии 86
      +2
      Да, спасибо. Пользовался этим и даже не знал как оно называется. А вот создание тру-приватных свойств очень даже интересно и познавательно.
        0
        Это не совсем тру-приватные свойства, но очень близко к ним.
          +2
          Обширная статья — побольше бы таких
          Только приватные переменные можно достать следующим образом:

          var MyModule = (function() {
          var field = 'Habrahabr';
          return {
          sayPrevedToHabrahabr: function() {
          alert(field);
          }
          }
          })();
          MyModule.sayPrevedToHabrahabr(); //alerts «PREVED Habrahabr»
          // получение псевдо-приватного поля
          var private_var;
          eval('private_var=field', MyModule.sayPrevedToHabrahabr);
          alert(private_var);
            +2
            Конечно, но в данном случае приватные переменные используются скорее для удобства программистов, которые будут поддерживать этот код, чем для секьюрити, поэтому это не так уж существенно.
              0
              И да это (т.е. eval(code, scope)) работает далеко не во всех браузерах (насколько знаю только в Firefox/gecko).
          +5
          Думаю еще будут полезными ссылки на статью Мартина Фаулера о замыканиях вообще (на англ.) martinfowler.com/bliki/Closure.html и Нила Гафтера об истории возникновения замыканий (тоже на англ.) gafter.blogspot.com/2007/01/definition-of-closures.html
          Кстати, узнав впервые что такое замыкания я наконец-то понял зачем в Java нужны inner classes.

          За статью спасибо, кроме самих замыканий интересно было узнать и про управление доступом в Javascript. На досуге почитаем поподробнее, занятная тема вообще
            0
            У Котерова статья была хорошая, для тех у кого трудно с английским.

          +1
          хорошая статья, спасибо
            0
            Скоро ещё выйдет книга в которой все эти вещи будут описаны «Secrets of the JavaScript Ninja» John Resig
            Вот примеры нескольких глав из книги:
            How closures work — ajaxian.com/downloads/books/javascriptninja/JavaScriptNinja_ch3_Article1.pdf
            Using (function(){})() — ajaxian.com/downloads/books/javascriptninja/JavaScriptNinja_ch3_Article2.pdf
            Class-Like Code — ajaxian.com/downloads/books/javascriptninja/JavaScriptNinja_ch5_Article2.pdf
              0
              Да-да, я тоже жду этой книги с нетерпением. :)
                0
                3 года ждем…
              0
              Замыкания — одно из самых сложных для понимания вещей, особенно для начинающих.
              Спасибо за хороший материал с объяснениями.

              4 абзац, видимо опечатка — «остаются доступными внутренней функцией функции»
                0
                Прошу прощения, хабр съел тэг strike, имелось ввиду вместо «функцией» -> «функции»
                  0
                  Думаю, тут подходят оба варианта — быть доступным чем-либо или чему-либо.
                  +2
                  Очень хорошая статья.
                  Хотелось бы добавить, что иногда замыкания могут послужить причиной мемори-ликов. Например в коде:

                  function createHelloFunction = function(name) {
                     var myBigObject = createSomeBigObject();
                  
                     return function() {
                        alert('Hello, ' + name);
                     }
                  }
                  
                  var sayHelloHabrahabr = createHelloFunction('Habrahabr');
                  


                  Хотя и myBigObject в возвращаемой функции не используется, ссылка на него остаётся (по крайней мере покуда жив sayHelloHabrahabr).
                  Вот более живой пример:

                  function attach()
                  {
                    var element = document.getElementById("my-element");
                    element.attachEvent("onclick", function(){ alert("Clicked: " + element.innerHTML); });
                  }
                  


                  Как с этим бороться можно почитать тут на английском.
                    0
                    Спасибо, дельное замечание.

                    Благодаря этому комментарию вдруг вспомнил о том, что хотел упомянуть про еще одну распространённую ошибку, связанную с замыканиями — добавил в конце статьи.
                    –6
                    Язык JS к сожалению хренова описан.
                    Что в нем есть замыкания( точнее что их тама можно написать ) я узнал только год назад, а что они есть в php так и всего пару месяцев как.

                    А вот годика 3 назад я познакомился в замыканиями в lua.
                    Это была жесть. Мы сидели всем офисом и медитировали.
                    На выходе часто получался код которые непонятно как, но работает
                    Потом привыкли, выучили страшные слова типа лямда-функция, узнали что «клошуре» это не «калоша» а «замыкание» ( уж не знаю почему 5 человек год даже не пытались перевести термин на русский)
                    Но всеже не спешим использовать замыкания и другие фокусы повсеместно.
                    — Приходят на работу люди сразу после института и начинаются «тупняк»
                    Не учат этой уличной магии в институте.
                    В указаных примерах магии особо нет, но если постараться ее можно придумать. Так вот — лучше не придумывайте. Морда проше — и люди потянутся
                    А изучившим магию бууста замыкания уже… поздно, человек уже сам замкнулся, не мыт, не брит… работает программист! отойдите! и не подкармивайте!
                    это опасно, может привязаться
                      0
                      Сударь! Я ваш фанат! Ржем всей комнатой :)
                        +2
                        Это не уличная магия, а благородное лямбда-исчисление.
                          0
                          >а что они есть в php так и всего пару месяцев как.
                          а в php их пару месяцев назад и небыло :)
                          +1
                          читал раньше здесь:
                          javascript.ru/tutorial/basic/closure#prostoie-opisaniie
                            –2
                            Если честно, мне кажется что автор несколько… перемудрил, что-ли. Если человек без достаточного опыта посмотрит на статью, то он просто — напросто может испугаться яваскрипта, заплакать и убежать. И тогда не исключено, что страна, да и весь мир, может потерять потенциального гениального программиста.

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

                            ИМХО неплохая статья для понимания смысла замыканий в JS лежит вот здесь — javascript.ru/tutorial/basic/closure
                              +4
                              Не знаю, не знаю… Я например JS всего месяца 4 изучаю и то от случая к случаю, однако статья меня совсем не напугала, а наоборот очень заинтересовала. Лично для меня она приоткрывает настоящий JS, а не просто средство для выпадающих менюшек и прочих украшательств.
                                0
                                Речь про то, что человек может начинать вообще изучение программирования (школьные годя чудесные не берем) с JS. Были же у многих цепочки такого рода: HTML -> JS -> PHP/Perl/ASP и т.д.
                                В таком случае эта статья его напугать может. ИМХО статья такого рода намного ценнее, если она пригодна наиболее широкой массе читателей, а не только тем, кто достиг относительно неплохого уровня.
                                  +1
                                  наверное Вы правы. Меня, как начавшего изучение программирования с Паскаля, такие вещи в JS не могут не радовать)))
                                    0
                                    Я начинал с Бэйсика, так что в общем и целом мне тоже статья понравилась. Но более простое изложение не сделало бы её хуже, а просто расширило бы круг читателей.
                                +1
                                О! Прошу прощения, только сейчас заметил, что линк уже был дан постом выше.
                                  0
                                  Да, по этой ссылке — тоже хорошая статья.

                                  Мне просто хотелось написать более-менее исчерпывающую и практичную статью по данному предмету, чтобы дать человеку возможность разобраться в нём основательно, узнав не только про то, что это такое и как выглядит, но и про то, как именно это используют в современной веб-разработке.
                                    +1
                                    Я и не отрицаю, что статья у Вас получилась, на мой взгляд, хорошая. Просто высказал своё мнение относительно подачи материала.
                                      0
                                      Спасибо. :) Я честно пытался выдумать более простые примеры и объяснения, но получилось как есть.
                                  0
                                  все-таки не
                                  function createHelloFunction = function(name) {
                                  а
                                  var createHelloFunction = function(name) {…

                                  Ну и для сохранений между вызовами проще использовать func_name.attr типа

                                  function countIt(reset) {
                                  if (reset ||! countIt.cnt) countIt.cnt = 0;
                                  return countIt.cnt++;
                                  }
                                    –3
                                    Замыкания все-таки удобней
                                    function countlt(reset) {
                                    var cnt = 0;
                                    countlt = function(reset) {
                                    if (reset) cnt = 0;
                                    return cnt++;
                                    };
                                    return countlt(reset);
                                    }
                                      0
                                      и чем это удобней? Кода больше — смысл тот же. Опять же про утечки думать надо.
                                      Замыкания очень приятная штука, но все ж не надо их вставлять там, где они не нужны.
                                        0
                                        Какие утечки? Если вы переменную будете хранить в свойстве, а не внутри функции, она меньше места от этого занимать не будет. Плюс недоступность переменной извне (для эстетов).
                                          0
                                          я храню переменную, а вы — переменную И функцию.
                                          вот тут уже написали habrahabr.ru/blogs/webdev/38642/#comment_919147
                                            0
                                            Ну во-первых, не функцию, а ее скоп. Во-вторых, где же тут утечка? Утечка — это когда в памяти лежит что-то, что не используется, в моем примере все используется. Ну и в-третьих, пример слишком простой, чтобы о нем спорить.

                                            Данный подход полезен, когда в функции нужно выполнять кучу условий, параметры которых не меняются в течение работы скрипта (обеспечение кроссбраузерности, например). Вот здесь script.shabunc.org/? p=33 хорошо описано.
                                      0
                                      Поправил, спасибо.

                                      Насчёт сохранения — ну это дело вкуса, кому что больше нравится. Мне скажем не нравится такой подход во-первых потому, что аттрибут можно легко подменить — переменные замыкания лучше изолированы от внешнего воздействия, а во-вторых потому, что для независимости от имени функции в вашем случае приходится писать arguments.callee.attr везде, а это куда менее красиво, чем просто attr в случае замыкания.
                                      0
                                      В который раз замечаю что javascript не так прост, как кажется на первый взгляд. Спасибо.
                                        +1
                                        а он прост. Но это не мешает ему быть мощным инструментом.
                                        0
                                        Хорошо )
                                          +1
                                          Спасибо большое, занес в избранное :)
                                            –3
                                            Понравилось, спасибо.
                                            Добавил в избранное.
                                              0
                                              Замыкания в Си :)
                                              lists.cs.uiuc.edu/pipermail/cfe-dev/2008-August/002670.html
                                                –11
                                                Javascript вскоре станет полноценным объектно-ориентированным языком. Здорово!
                                                  0
                                                  не станет, пока! Новая версия стандарта придерживается той же идеологии. ECMAScript драфт 4, который ООП-style, не приняли. Недавно весь инет гудел по этому поводу.
                                                    0
                                                    Ну вообще-то разработчики ECMAScript Harmony пока что не решили этот вопрос до конца — вполне возможно, что там будут фичи на уровне языка для классической модели ООП, просто в упрощенном варианте.
                                                    Вот здесь об этом можно почитать: ejohn.org/blog/ecmascript-harmony/
                                                      0
                                                      я ж и не говорил, что до конца. Факт в том, что новая версия стандарта принята, и в этой версии идеология таже.
                                                        0
                                                        Нет, вы утверждали, что JavaScript не станет полноценным ООП-языком из-за того, что отбросили ECMAScript 4. Я же говорю, что данное утверждение неверно, поскольку ECMAScript 3.1 еще в разработке и вполне может получить такие возможности — этот вариант там активно рассматривается.
                                                          0
                                                          у меня инфа, что новый стандарт утвержден
                                                            0
                                                            Вы что, смеетесь?
                                                            Перечитайте внимательно, пожалуйста, текст по вышеприведенной ссылке.
                                                      0
                                                      en.wikipedia.org/wiki/Prototype-based_programming
                                                      Далее покупаем книжки «Structure and Interpretation of Computer Programs» и «Concepts, Techniques, and Models of Computer Programming», укладываем мысли в порядок и не обращаем внимания на «программистов» без образования…
                                                      0
                                                      Боже, упаси!
                                                      0
                                                      Возник вопрос. Зачем яваскриптовый интерпритатор сохраняет и не очищает память от неиспользуемых объектов? (либо я не правильно понимаю)

                                                      Рассмотрим простой синтетический пример

                                                      function createFunction = function() {
                                                      // много очень тяжелых объектов, которые много памяти съедают
                                                      var obj1 = new Obj1();
                                                      var obj2 = new Obj2();
                                                      var obj3 = new Obj3();
                                                      // Возвращаемое значение
                                                      return function(){
                                                      alert('Я простая функция, и не использую никакие внутренние объекты');
                                                      }
                                                      }

                                                      // использование
                                                      var func = createFunction();

                                                      В этом случае хранятся все объекты, которые созданы внутри. Зачем так сделано? Ведь они не используются в самой функции. По сути создается некая сущность, результатом работы которой является простая функция. Интерпритатор это хорошо знает. Для каких целей хранить все остальное в памяти?

                                                      Либо, если можно, приведите пример того, как можно воспользоваться внутренними объектами извне? Не уже ли это сделано для того, чтобы дать возможность менять прототип функции и объектная модель при этом не портилась? То есть, чтобы можно было добавить или переобпределить эту самую функцию?… вот, хотелось бы увидеть наглядный пример
                                                        0
                                                        для подстраховки от таких штук:

                                                        return function(){
                                                        var str= 'alert(obj1)';
                                                        eval( str );
                                                        }

                                                          +1
                                                          Если «я простая функция и не использую никакие внутренние объекты», то зачем мне быть внутри? Значит место моё тоже должно быть простым — снаружи… ну, или внутри функции, не насыщенной так сильно переменным и т.д.
                                                            0
                                                            Предполагаю, что garbage collection в современных браузерах достаточно умна, чтобы делать объекты доступными для чистки, если на них в коде не осталось ссылок из замыканий. Но вообще на практике это не так существенно, потому что ситуации, когда замыкание не использует объектов выше, достаточно редкие. А если всё-таки возникают, лишние переменные можно опять же окружить замыканием и вне его они не попадут:

                                                            (function() {
                                                            var obj1 = new Obj1();
                                                            var obj2 = new Obj2();
                                                            var obj3 = new Obj3();
                                                            })();
                                                            return function…

                                                            Извне внутренними объектами не нужно пользоваться, они используются внутри функции при формирования результата вызова. Насчёт примера — не совсем понял, какой вам нужен пример кроме тех, что показаны в статье, объясните, пожалуйста.
                                                            –4
                                                            (for var i = 0; i < links.length; i++) {
                                                            //(function(i) {
                                                            var k= i;
                                                            links[k].onclick = function() {
                                                            alert(k);
                                                            }
                                                            //})(i);
                                                            }

                                                            не надо делать двойных замыканий ;-)
                                                              0
                                                              а вы пробовали этот код исполнять? хехе :)
                                                                +1
                                                                Замыкания «не помнят» конкретного значения, поэтому введение переменной 'k' не имеет большого смысла, значение нужно «сохранять» или обернув функцией (как в примере), или другими способами…
                                                                  0
                                                                  не, моя ошибка тут заключалась в том, что я думал, буд-то тело цикла имеет собственный скоп, как в любом нормальном яп…
                                                                    0
                                                                    Иначе я бы этой проблемы не упоминал :)
                                                                    Собственный скоуп в JS только у функций.
                                                                +3
                                                                > (for var i = 0; i < links.length; i++)

                                                                Lisp || JS —?

                                                                %)
                                                                  0
                                                                  Упс, поправил, спасибо. :)
                                                                • НЛО прилетело и опубликовало эту надпись здесь
                                                                    –10
                                                                    Во вступительном посте:
                                                                    … js — функциональный язык программирования (не путать с процедурным). Не совсем, конечно, чистый функциональный язык, но основные моменты присутствуют.


                                                                    Что курил автор?
                                                                    • НЛО прилетело и опубликовало эту надпись здесь
                                                                  0
                                                                  Хорошая статья, спасибо! добавлю в избранное и сохраню в копилочку ))
                                                                    0
                                                                    Доступ к переменным не локальной области видимости требует больших затрат… не увлекайтесь замыканиями без надобности… хотя на простеньких задачах, коих большинство это неважно.
                                                                    Кстати прятать код с локальными переменными и обьектами можно не только в анонимной функции

                                                                    (function(){
                                                                    //ваш спрятанный код
                                                                    }();

                                                                    но и в анонимном конструкторе обьекта два байта короче :-) и читается легче

                                                                    new function(){
                                                                    //ваш спрятанный код
                                                                    };

                                                                    точку с запятой не забывайте иначе при сжатии кода могут быть проблемы.
                                                                      0
                                                                      >Доступ к переменным не локальной области видимости требует больших затрат

                                                                      Буду рад увидеть ссылку на подтверждающие это бенчмарки. :)
                                                                    0
                                                                    > Следующее, принципиально иное применение замыканий — защита данных.
                                                                    Это называется инкапсуляция.

                                                                    Спасибо за хорошую статью!
                                                                    • НЛО прилетело и опубликовало эту надпись здесь
                                                                        0
                                                                        Про новые фичи JS 1.7 можно вообще много всего написать, но я хотел сосредоточиться на наиболее практичных моментах.
                                                                          0
                                                                          А какие именно, не подскажете?
                                                                          0
                                                                          Спасибо за статью очень интересно.
                                                                          Как Вам такая комбинация?

                                                                          function some() {
                                                                          ........var self = arguments.callee;
                                                                          ........if(!self.clk) {//Инициализация выполняется только один раз
                                                                          ................self.clk = function() {alert(this.i)}
                                                                          ........}
                                                                          ........for (var i = 0; i < links.length; i++) {
                                                                          ................links[i].onclick = self.clk.bind({i:i})
                                                                          ........}
                                                                          }

                                                                          функция self.clk опеределяется один раз для всех
                                                                          Как думаете, будет ли выигрыш в производительности при таком подходе?
                                                                            0
                                                                            Будет. В принципе многие применения замыканий можно заменить использованием arguments.callee, но я считаю этот подход куда менее изящным. :)
                                                                              0
                                                                              Тем более, что 5-я редакция ECMAScript запрещает использование arguments.callee() в строгом (strict) режиме.
                                                                            0
                                                                            var MyModule = (function() {
                                                                               var name = 'Habrahabr';
                                                                               function sayPreved() {
                                                                                  alert('PREVED ' + name.toUpperCase());
                                                                               }
                                                                               return {
                                                                                  sayPrevedToHabrahabr: function() {
                                                                                     sayPreved(name);// [ 8 ]
                                                                                  }
                                                                               }
                                                                            })();
                                                                            MyModule.sayPrevedToHabrahabr();

                                                                            В 8-й строке (я ее пометил комментом [ 8 ]) вызов ф-ии sayPreved() делается с параметром name.
                                                                            Это смысловая опечатка или нет (если необходимо, то зачем)? (у меня сработало и с вызовом без параметра)
                                                                              0
                                                                              Вы правы, случайно ошибся. :) Там в функции sayPreved нужно добавить аргумент name. Хотя оно и так и так работает — я просто хотел продемонстрировать, что из sayPrevedToHabrahabr доступны и ф-я, и переменная.
                                                                              0
                                                                              Спасибо! Очень полезно!
                                                                                0
                                                                                За статью спасибо) Просто и понятно.
                                                                                  0
                                                                                  Очень хорошая статья — только она смогла боле-менее упорядочить в голове весь бардак, сгенерированный просмотром исходников jQuery.
                                                                                    0
                                                                                    Кто-нибудь, подскажите, пожалуйста, я не очень понимаю, зачем использовать замыкание для инкапсуляции:
                                                                                    Решил проверить, что пример с sayPrevedToHabrahabr действительно помогает инкапсулировать методы и свойства MyModule.
                                                                                    Для этого создал функцию:
                                                                                    function MyModule() {
                                                                                       var name = 'Habrahabr';
                                                                                       function sayPreved() {
                                                                                          alert('PREVED ' + name.toUpperCase());
                                                                                       }
                                                                                       this.sayPrevedToHabrahabr = function() {
                                                                                             sayPreved(name);
                                                                                       };
                                                                                    };
                                                                                    


                                                                                    Далее создал объект
                                                                                    var myModule = new MyModule();
                                                                                    

                                                                                    и попробовал обратиться к его локальным переменным и методам:
                                                                                    document.writeln(myModule.name); // undefined
                                                                                    document.writeln(myModule.sayPreved()); // Uncaught TypeError: undefined is not a function on line 15
                                                                                    


                                                                                    Может быть, локальная функция создалась в глобальной области видимости?
                                                                                    попробовал sayPreved(), но это так же падает с ошибкой.

                                                                                    Зачем же в таком случае использовать замыкания для инкапсуляции данных, если последние и так недоступны из вне?

                                                                                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                                    Самое читаемое