Это включает закрытия JavaScript?

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

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

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

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

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('
'); $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); }());

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

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

Спасибо

Обновление

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

return {
    scrollDown: scrollDown
};

Это могло затем быть, если бы я хотел сделать текстовую прокрутку по сравнению с где-нибудь еще в JavaScript, то я мог бы сделать

pageScroll.scrollDown();

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

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

10
задан alex 15 April 2010 в 14:50
поделиться

10 ответов

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

  • Локально определенные переменные родительской функции
  • Аргументы родительской функции
  • Локальные переменные и аргументы родительской функции и т. Д.
  • Глобальные переменные

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

        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"
12
ответ дан 3 December 2019 в 18:32
поделиться

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

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

1
ответ дан 3 December 2019 в 18:32
поделиться

Какой день, чтобы не использовать мою книгу Javascript: The Good Parts ...

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

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

YouTube-ролик о Javascript: The Good Parts

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

0
ответ дан 3 December 2019 в 18:32
поделиться

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

2
ответ дан 3 December 2019 в 18:32
поделиться

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

         <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>

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

1
ответ дан 3 December 2019 в 18:32
поделиться

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

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

 func(); //alert 'Hi There', eventhough the outter function has exit
0
ответ дан 3 December 2019 в 18:32
поделиться

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

0
ответ дан 3 December 2019 в 18:32
поделиться

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

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

1
ответ дан 3 December 2019 в 18:32
поделиться

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

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

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

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

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

3
ответ дан 3 December 2019 в 18:32
поделиться

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

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

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

1
ответ дан 3 December 2019 в 18:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: