Подтвердить что ты не робот

Каковы преимущества использования анонимных функций вместо названных функций для обратных вызовов и параметров в коде событий JavaScript?

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

Что-то, что всегда казалось мне странным, заключается в том, что, несмотря на кошмар читаемости, который является гнездом JavaScript-вложенных обратных вызовов, одна вещь, которую я очень редко вижу во многих примерах и учебниках, - это использование предопределенных названных функций как обратного вызова аргументы. Я программист на Java, и отбрасывает стереотипные удары о именах Enterprise-y для единиц кода, одна из вещей, которые я пришла чтобы наслаждаться работой на языке с сильным выбором функциональной среды IDE, заключается в том, что использование значимых, если долгое, имен может сделать смысл и смысл кода более понятным, не делая его более сложным, чтобы быть действительно продуктивным. Так почему бы не использовать тот же подход при написании кода JavaScript?

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

Плюсы:

  • Гибкость. Асинхронная функция с параметром обратного вызова может быть достигнута одним из многих различных путей кода, и ее можно было бы использовать, чтобы написать именованную функцию для учета всех возможных возможных случаев.
  • Скорость. Он сильно влияет на хакерский менталитет. Задвиньте вещи до этого, пока это не сработает.
  • Все остальные делают это
  • Меньшие размеры файлов, даже если они тривиально, но каждый бит подсчитывается в Интернете.
  • Упрощенный АСТ? Я бы предположил, что анонимные функции генерируются во время выполнения, поэтому JIT не будет гадать с сопоставлением имени с инструкциями, но я просто догадываюсь об этом.
  • Быстрая отправка? Не уверен в этом. Угадайте еще раз.

Минусы:

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

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

Итак, есть ли какие-либо технические причины или ошибки, о которых я не знаю, делает эту практику настолько обыденной по какой-либо причине?

4b9b3361

Ответ 1

Я использую анонимные функции по трем причинам:

  • Если имя не требуется, потому что функция вызывается только в одном месте, то зачем добавлять имя в любое пространство имен, в котором вы находитесь.
  • Анонимные функции объявляются встроенными, а встроенные функции имеют преимущества в том, что они могут обращаться к переменным в родительских областях. Да, вы можете поместить имя в анонимную функцию, но это обычно бессмысленно, если оно объявлено inline. Таким образом, встроенный имеет значительное преимущество, и если вы делаете встроенный, нет оснований указывать на нем имя.
  • Код выглядит более автономным и читаемым, когда обработчики определяются прямо внутри кода, вызывающего их. Вы можете читать код почти последовательно, а не искать функцию с этим именем.

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

Я бы добавил, что если обратный вызов начнет получать более 15-20 строк и ему не нужен прямой доступ к переменным в родительской области, у меня возникнет соблазн дать ему имя и сломать это в свою собственную именованную функцию, объявленную в другом месте. Здесь определенно есть читаемость, где нетривиальная функция, которая становится длинной, просто более удобна в обслуживании, если она помещается в свой собственный именованный блок. Но большинство обратных вызовов, которые я получаю, не так уж и длинны, и я считаю его более читаемым, чтобы держать их в строгом соответствии.

Ответ 2

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

Я буду использовать эту функцию где-нибудь еще?

Если да, я называю/определяю его. Если нет, передайте его как анонимную функцию.

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

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

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

Предположим, что обе эти функции выполняют одно и то же:

function addTimes(time1, time2)
{
    // return time1 + time2;
}

function addTwoTimesIn24HourFormat(time1, time2)
{
    // return time1 + time2;
}

Второй говорит вам, что именно он делает в названии. Первый - более двусмысленный. Однако в названии есть 17 символов. Скажем, что функция вызывается 8 раз по всему коду, что 153 дополнительных байта для вашего кода не требуется. Не колоссально, но если это привычка, экстраполируя это на 10 или даже 100 функций, легко будет означать несколько килобайт разницы в загрузке.

Однако, тем не менее, ремонтопригодность следует сопоставлять с преимуществами производительности. Это боль, связанная со сценарием.

Ответ 3

Ну, только для того, чтобы быть ясными ради моих аргументов, в моей книге все анонимные функции/выражения функций:

var x = function(){ alert('hi'); },

indexOfHandyMethods = {
   hi: function(){ alert('hi'); },
   high: function(){
       buyPotatoChips();
       playBobMarley();
   }
};

someObject.someEventListenerHandlerAssigner( function(e){
    if(e.doIt === true){ doStuff(e.someId); }
} );

(function namedButAnon(){ alert('name visible internally only'); })()

Плюсы:

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

  • Победимость разбора кода: в примере объектного литерала с помощью anon funcs, назначенных как методы, было бы глупо добавлять больше мест для поиска и клевать для логики в вашем коде, когда вся точка этого объектного литерала чтобы перекрыть некоторые связанные функции в том же удобном месте. Однако при объявлении публичных методов в конструкторе я обычно определяю помеченные функции inline, а затем назначаю в качестве ссылок this.sameFuncName. Это позволяет мне использовать одни и те же методы внутри себя без этого. cruft и делает порядок определения беззаботным, когда они называют друг друга.

  • Полезно избегать ненужного глобального загрязнения пространства имен. Однако внутренние пространства имен никогда не должны быть настолько широко заполнены или обработаны несколькими командами одновременно, чтобы аргумент казался мне немного глупым.

  • Я согласен с встроенными обратными вызовами при настройке коротких обработчиков событий. Глупо прибегать к функции 1-5 строк, тем более, что с JS и функцией hoisting определения могут заканчиваться где угодно, даже в том же файле. Это может произойти случайно, не нарушая ничего, и нет, вы не всегда можете контролировать этот материал. События всегда приводят к срабатыванию функции обратного вызова. Нет причин добавлять дополнительные ссылки на цепочку имен, которые нужно сканировать, просто для обратного проектирования простых обработчиков событий в большой базе данных кода, а проблема трассировки стека может быть решена путем абстрактного запуска триггеров событий в методы, которые записывают полезную информацию при отладке режим включен и запускает триггеры. Я действительно начинаю строить целые интерфейсы таким образом.

  • Полезно, если вы ХОЧИТЕ порядок определения функции. Иногда вы хотите быть уверенным в том, что функция по умолчанию - это то, что вы думаете до тех пор, пока не будет определен код в коде, где можно переопределить его. Или вы хотите, чтобы поломка была более очевидной, когда зависимости перетасовываются.

Минусы:

  • Функции Anon не могут воспользоваться функцией подъема. Это большое различие. Я склонен к тому, чтобы воспользоваться преимуществами подъема, чтобы определить мои собственные явно названные funcs и конструкторы объектов в нижней части и перейти к определению объекта и элементам основного цикла вверху. Я нахожу, что код упрощает чтение, когда вы хорошо назовете ваши вары и получите широкое представление о том, что происходит до ctrl-Fing, для получения подробной информации, только если это имеет значение для вас. Подъем также может быть огромным преимуществом в сильно управляемых событиями интерфейсах, где наложение строгого порядка того, что доступно, когда может укусить вас в прикладе. Подъем имеет свои собственные предостережения (например, круглый опорный потенциал), но это очень полезный инструмент для организации и создания четкого кода при правильном использовании.

  • Четкость/Debug. Абсолютно они слишком часто используются слишком часто, и это может привести к отладке и четкости кода. Кодовые базы, которые в значительной степени зависят от JQ, могут быть серьезной PITA для чтения и отладки, если вы не инкапсулируете почти неизбежные анонсы тяжелого и массово перегруженного аргумента супа в разумном ключе. Например, метод наведения JQuery является классическим примером чрезмерного использования функций anon, когда вы бросаете в него две функции anon, поскольку для первого таймера легко использовать его как стандартный метод назначения прослушивателя событий, а не один метод, перегруженный для назначения обработчиков для одного или двух событий. $(this).hover(onMouseOver, onMouseOut) намного понятнее, чем две функции anon.

Ответ 4

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

(function recursion(iteration){
    if (iteration > 0) {
      console.log(iteration);
      recursion(--iteration);
    } else {
      console.log('done');
    }
})(20);

console.log('recursion defined? ' + (typeof recursion === 'function'));

http://jsfiddle.net/Yq2WD/

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

Привет, меня зовут Джейсон ИЛИ привет, меня зовут???? вы выбираете.

Ответ 5

Немного поздно для вечеринки, но некоторые еще не упомянули аспекты функций, анонимные или иначе...

Анионные функции не просто упоминаются в гуманоидных разговорах о коде, среди команды. Например, "Джо, не могли бы вы объяснить, что делает алгоритм, в пределах этой функции... Какая из них - 17-я анонимная функция внутри функции fooApp... Нет, не тот! 17-й!"

Anon funk также анонимны для отладчика. (duh!) Следовательно, трассировка стека отладчика обычно просто показывает вопросительный знак или аналогичный, что делает его менее полезным, когда вы устанавливаете несколько точек останова. Вы попадаете в точку останова, но найдите прокрутку окна отладки вверх/вниз, чтобы выяснить, где, черт возьми, вы находитесь в своей программе, потому что эй, функция вопросительного знака просто этого не делает!

Проблемы, связанные с загрязнением глобального пространства имен, действительны, но легко устраняются путем присвоения имен вашим функциям в качестве узлов внутри вашего собственного корневого объекта, например "myFooApp.happyFunc = function (...) {...};".

Функции, доступные в глобальном пространстве имен, или как узлы в корневом объекте, как указано выше, могут быть вызваны из отладчика напрямую, во время разработки и отладки. Например, в командной строке консоли выполните "myFooApp.happyFunc(42)". Это чрезвычайно мощная способность, которая не существует (изначально) в скомпилированных языках программирования. Попробуйте это с помощью функции anon.

Anon funcs можно сделать более читаемыми, присвоив их var, а затем передав var как обратный вызов (вместо inlining). Например.:   var funky = function (...) {...};   JQuery ( '# Отис') нажмите (фанк).

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