Включает ли это закрытие JavaScript?

В попытке изучить закрытие JavaScript я немного смутил себя.

Из того, что я собрал по сети, закрытие...

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

Вот небольшой пример script из недавнего проекта. Он позволяет прокручивать текст в div с помощью кнопок вверх и вниз.

var pageScroll = (function() {

    var $page,
        $next,
        $prev,
        canScroll = true,
        textHeight,
        scrollHeight;

    var init = function() {

        $page = $('#secondary-page');

        // reset text 
        $page.scrollTop(0);

        textHeight = $page.outerHeight();

        scrollHeight = $page.attr('scrollHeight');

        if (textHeight === scrollHeight) { // not enough text to scroll

            return false;    

        };

        $page.after('<div id="page-controls"><button id="page-prev">prev</button><button id="page-next">next</button></div>');

        $next = $('#page-next');

        $prev = $('#page-prev');

        $prev.hide();

        $next.click(scrollDown);

        $prev.click(scrollUp);

    };

    var scrollDown = function() {

        if ( ! canScroll) return;

        canScroll = false;

        var scrollTop = $page.scrollTop();

        $prev.fadeIn(500);

        if (scrollTop == textHeight) { // can we scroll any lower?

            $next.fadeOut(500);

        }

        $page.animate({ scrollTop: '+=' + textHeight + 'px'}, 500, function() {

            canScroll = true;

        });    

    };

    var scrollUp = function() {

        $next.fadeIn(500);

        $prev.fadeOut(500);

        $page.animate({ scrollTop: 0}, 500);    


    };

    $(document).ready(init);

}());

В этом примере используются замыкания? Я знаю, что он имеет функции внутри функций, но существует ли случай, когда используются внешние переменные?

Я использую их, не зная об этом?

Спасибо

Update

Будет ли это делать замыкание, если я разместил это под оператором $(document).ready(init);?

return {
    scrollDown: scrollDown
};

Может быть, если бы я хотел, чтобы текст прокручивался из любого места в JavaScript, я мог бы сделать

pageScroll.scrollDown();

Другое обновление

Ничего себе, похоже, что это сработало! Вот код на JSbin. Обратите внимание, что скроллер страницы не работает точно в этом примере (он, похоже, не подходит к нижней части текста), но это нормально:) Бонусные баллы для всех, кто может сказать мне, почему он не прокручивается донизу.

Ответ 1

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

  • Родительская функция, локально заданная переменная
  • Аргументы родительской функции
  • Родительская функция родительская функция локальных варов и аргументов и т.д.
  • Глобальные переменные

Реальное значение замыканий заключается в возврате внутренней функции, которая захватила закрытую переменную, которая не изменится, например:

        function test (value){
            return function(){
                alert(value); //using enclosed argument
            }
        }

        var t1 = test("first");
        var t2 = test("second");
        t1();//alerts "first"
        t2();//alerts "second"

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

function makeArray (){
    var result=[]
    for (var i =0; i < 3; ++i){
        result.push(function(){
            alert("function #" +i); //using enclosed i
        })
    }
    return result;
}

var fnArray =makeArray();
fnArray[0]();//alerts "function #3"
fnArray[1]();//alerts "function #3"
fnArray[2]();//alerts "function #3"

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

function makeArray (){
    var result=[]
    var wrapFunction=function (counter){
        return  function(){
            alert("function #" +counter); //using enclosed counter
        }
    }
    for (var i =0; i < 3; ++i){
        result.push(wrapFunction(i))
    }
    return result;
}

var fnArray =makeArray();
fnArray[0]();//alerts "function #0"
fnArray[1]();//alerts "function #1"
fnArray[2]();//alerts "function #2"

Ответ 2

Взгляните на блог-дневник Дмитрия А. Сошникова о ECMA-262 ( "javascript" ).

Сообщение 6 http://dmitrysoshnikov.com/ecmascript/chapter-6-closures/ касается закрытий, и если вы читаете предыдущие сообщения, вы должны хорошо понять его.

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

Понятие "замыкание" появляется, когда вы создаете ссылку на такую ​​содержащуюся функцию за пределами цепочки видимости, либо путем возврата ссылки на функцию, либо путем добавления ссылки на нее как свойство на объект выше в цепочке охвата. [чтобы вы, вызвав функцию (по этой ссылке), могли изменять переменные, скрытые внутри недоступной области.]

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

Ответ 3

Я не думаю, что вы используете какие-либо закрытия, потому что вы не возвращаете внутренние функции из своей внешней функции, поэтому эти переменные всегда будут в области видимости, когда их вызывают. Другими словами, init(), scrollDown() и scrollUp() должны быть вызваны из pageScroll(). Если pageScroll() возвращал любую из трех своих внутренних функций, а затем вы вызывали их вне pageScroll(), использование переменных $page, $next, $prev и т.д. Было бы закрытием. Я думаю.

Ответ 4

Я не эксперт по Javascript, но из того, что я прочитал здесь, да, у вас есть закрытие.

Обратите внимание, что все внутренние функции совместно используют переменную $page, например. init назначает ему, а затем функции прокрутки обновляют его. Поэтому в принципе внутренними функциями являются замыкания внешней функции. Внешняя функция передает init в document.ready, поэтому в некоторых вариантах Javascript-ish возвращается закрытие.

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

Ответ 5

Вы присоединяете к событию onclick элемента #page-next функцию scrollDown, которая хранит ссылку на переменную canScroll вашего объекта pageScroll. Так что да, у вас есть закрытие.

На самом деле в вашем примере есть 4 закрытия: функция, отправленная на $next.click, отправленная на $prev.click, отправленная на $page.animate, и отправленная на $(document).ready.

Ответ 6

Да, у вас есть закрытие, посмотрите на этот быстрый пример

         <script type="text/javascript">
    var t1=null;
    function test(){
        alert('Test');
        var x  = 10;
        t1 =  function(){
            alert('x='+ x);
        };  
    };
    function test2(){
        t1();
    }
    </script>
    <a href="javascript:test();">Test me 1 </a>  

<a href="javascript:test2();">Test me 2</a>

Closures имеют доступ к своим родительским переменным, в этом случае наша функция 't1' обращается к объявленному частным образом var x; также как вы заявили, что "внутренняя функция имеет доступ к своим родительским функциям, даже после того, как родительская функция вернулась". когда вы нажмете "Test me 2", вы получите предупреждение с x = 10, даже те, которые функция test() уже вернула, это имеет смысл.

Ответ 7

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

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

Ответ 8

Да, конечно, есть замыкания. Например, вы используете $page, $next и т.д., Объявленные в области вне, например, init (который их использует).

Ответ 9

Какой день не принести свой Javascript: книга "Хорошие детали" для работы...

Я считаю, что короткий ответ "Нет" из-за этой части определения: "даже после того, как эта родительская функция вернулась". Но я не уверен на 100%.

Это может помочь.

Клип YouTube Javascript: Хорошие детали

http://www.youtube.com/watch?v=hQVTIJBZook&feature=player_embedded

Ответ 10

очевидно, да... когда u вложил функцию внутри другой функции, u имеет замыкание. thats it

var func = (function(){
             var txt = 'Hi There!'
             return function(){
               alert(txt);
             }
           })();

 func(); //alert 'Hi There', eventhough the outter function has exit