Почему я все ещё использую function в JavaScript?

Предлагаю читателям «Хабрахабра» вольный перевод статьи «Constant confusion: why I still use JavaScript function statements» от Билла Суро (Bill Sourour).

В далеких 90-х, когда я только изучал JavaScript, мы пытались писать «Hello World» с помощью оператора function. Примерно так:

function helloWorld() {
  return ‘Hello World!’;
}

В настоящее же время крутые ребята пишут функцию “Hello World” вот так:

const helloWorld = () => 'Hello World!';

Здесь используется стрелочная функция, добавленная в JavaScript в стандарте ES2015. Она выглядит чертовски прекрасно. Всё умещается в одну строку. Так кратко. Так замечательно.

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

Когда я впервые их увидел, я выглядел примерно как Фрай из Футурамы

image
Даже если учесть, что Babel бесплатен

Так вот, спустя 20 лет изучения JavaScript и после начала использования ES2015 в некоторых проектах, как думаете, каким же образом я напишу Hello World сегодня? Вот так:

function helloWord() {
  return ‘Hello World!’;
}

После того как я показал вам новый способ, вы едва ли станете даже смотреть на код “старой школы”, представленный выше.

Целых 3 строчки на такую маленькую простую функцию?! Зачем здесь столько лишних символов?

Я знаю о чем вы думаете:

image
Ни у кого нет времени на это!

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

Надеюсь из этой цитаты Мартина “Дяди Боба” станет понятно, зачем же я это делаю.

Отношение времени, потраченного на чтение кода, по отношению ко времени, потраченному на его написание, составляет 10 к 1. Мы постоянно читаем наш старый код во время работы над новым кодом.

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

Роберт Мартин: Чистый код: создание, анализ и рефакторинг

Оператор function имеет 2 явных преимущества по сравнению со стрелочными функциями.

Преимущество №1: Ясность намерения


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

Взгляните на это:

const maxNumberOfItemsInCart = ...;

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

const maxNumberOfItemsInCart = 100;

… так и:

const maxNumberOfItemsInCart = (statusPoints) => statusPoints * 10;

Если же вы используете оператор function, то никакой двусмысленности уже не будет.

Взгляните на:

const maxNumberOfItemsInCart = 100;

… против:

function maxNumberOfItemsInCart(statusPoints) {
  return statusPoints * 10;
}

Намерения программиста ясны с самого начала строки.

Возможно вы используете редактор кода с подсветкой синтаксиса. Может вы быстро читаете. Скорее вы просто думаете, что не получите большого преимущества от добавления пары строчек.

Я вас понимаю. Краткая запись все еще выглядит довольно привлекательно.

На самом деле, если бы это являлось моей единственной причиной, то я бы смог убедить себя, что читабельностью можно пожертвовать.

Но все же это не единственная моя причина.

Преимущество №2: Порядок объявления == Порядок выполнения


В идеальном случае, я хотел бы объявлять мой код примерно в том порядке, в котором я хочу, чтобы он выполнялся.

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

image
Приготовьтесь к куче тарабарщины, которая должна доказать (надеюсь), что я разбираюсь в том, о чем говорю

Единственная вещь, которую вы должны уяснить в том, что написано ниже, это то, что вы не можете использовать const до того, как вы объявите её.

Данный код вызовет ошибку:

sayHelloTo(‘Bill’);
const sayHelloTo = (name) => `Hello ${name}`;

Все потому что в тот момент, когда движок JavaScript считает код, то он сделает привязку для функции «sayHelloTo», но не проинициализирует её.

Все объявления в JavaScript привязываются на ранней стадии, но инициализируются они в разное время. Другими словами, JavaScript привязывает объявление константы «sayHelloTo» — считывает ее, перемещает наверх и выделяет место в памяти под ее хранение — но при этом не устанавливает ей какого-либо значения до того момента, пока не дойдет до нее в процессе выполнения.

Время между привязкой «sayHelloTo» и ее инициализацией называется «временная мертвая зона» (temporal dead zone — TDZ).

Если вы используете ES2015 прямо в браузере, не переводя код в ES5 с помощью Babel, представленный ниже пример также выдаст ошибку:

if(thing) { 
  console.log(thing);
}
const thing = 'awesome thing';

Если же заменить здесь const на var, то мы не получим ошибки. Дело в том, что переменные инициализируются со значением undefined сразу во время привязки, в отличие от констант. Но что-то я отвлекся…

Оператор function, в отличие от const, не страдает от проблемы TDZ. Данный код будет валидным:

sayHelloTo(‘Bill’);
function sayHelloTo(name) {
  return `Hello ${name}`;
}

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

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

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

Большая часть кода написана людьми. Так что стоит учитывать то, что понимание большинства людей напрямую связано с порядком выполнения.

По факту, разве не будет прекрасно, если мы предоставим краткую сводку небольшой части нашего API в начале нашего кода? С оператором function мы легко можем это сделать.

Посмотрите на этот (отчасти выдуманный) модуль для корзины товаров…

export {
  createCart,
  addItemToCart,
  removeItemFromCart,
  cartSubTotal,
  cartTotal,
  saveCart,
  clearCart,
}
function createCart(customerId) {...}
function isValidCustomer(customerId) {...}
function addItemToCart(item, cart) {...}
function isValidCart(cart) {...}
function isValidItem(item) {...}
...

Со стрелочными функциями он будет выглядеть как-то так:

const _isValidCustomer = (customerId) => ...
const _isValidCart = (cart) => ...
const _isValidItem = (item) => ...
const createCart = (customerId) => ...
const addItemToCart = (item, cart) => ...
...

export {
  createCart,
  addItemToCart,
  removeItemFromCart,
  cartSubTotal,
  cartTotal,
  saveCart,
  clearCart,
}

А теперь представьте, что это большой модуль с огромным количеством небольших внутренних функций. Что вы предпочтете в таком случае?

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

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

Так что же насчёт стрелочный функций?


Да. Они все еще прекрасны.

Я обычно использую стрелочные функции для передачи небольшой функции в качестве значения для функции уровнем выше. Я использую их с promise, с map, с filter, с reduce. Именно здесь они будут являться прекрасным выбором.

Вот некоторые примеры:

const goodSingers = singers.filter((singer) => singer.name !== 'Justin Bieber');
function tonyMontana() {
  return getTheMoney().then((money) => power)
                                     .then((power) => women);
}

На этом я пожалуй и закончу. Спасибо за чтение!
Поделиться публикацией
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама
Комментарии 88
  • –17

    CoffeeScript снимает вопрос. Но мода прошла, к сожалению.

    • +19
      IE6 снимает вопрос еще более радикально. Но мода прошла, к сожалению.
      • –3

        ClojureScript еще более радикально снимает вопрос. И мода побоку.

        • +7
          Я скептически отношусь к «надстройкам» над js. Рано или поздно все они устаревают, и разработчик остается с мегабайтами эзотерического когда, который надо поддерживать.
          • +1
            ClojureScript устареет не раньше Clojure, и да, Clojure+ClojureScript это альтернативная Node.js реализация идеи «пишем клиент и сервер на одном языке»
            • +2
              А откуда у вас уверенность, что Clojure не забросят в 2018? Я не хочу говорить ничего плохого про этот язык, но вдруг.
              На стороне чистого js — огромная экосистема, сообщество и монополия на выполнение в браузере. Я считаю, можно быть уверенным, что в 2018 ES продолжат активно развивать.
              • 0
                Проблема только в том что на чистом js мало кто пишет сложные приложения. А проблема того что в 2018 забросят сегодня популярный очередной фреймворк, актуальна для js в первую очередь.
                • +2
                  Вы смешиваете язык и фреймворк. Приложения на React, Angular и т. д. как правило пишут на чистом js. Замена фреймворка — это намного меньший напряг, чем замена языка. Компании будет легче найти специалиста со знанием более мейнстримового языка.
                  • +1
                    В случае JavaScript к сожалению все несколько сложнее. Фреймворки для него отличаются идеологически. Чтоб далеко не ходить: React+redux — ФП идеология, Angular — ООП. Возможно субъективно, но для меня проще начать писать на coffeescript или TS чем сменить фреймворк который поставит с ног на голову все то к чему я привык.
                    • 0

                      ООП это скорее к Ember чем к Angular.

                    • 0

                      Написанное Angular назвать чистым JS сложно (хотя бывают приятные исключения). React и вовсе на jsx пишут, однако, если есть flux/redux части, то там довольно чистенько.

                      • –1
                        В Angular они переписали половину стандартной библиотеки, увлеклись, наверное. Но в нем можно теоретически писать и на чистом js.
                        В React на jsx стоит писать только вывод html.
                        • –1

                          Просто начинали-то писать во времена IE8, да и npm еще только зарождался, отсюда и всякие isUndefined и прочая ересь. Теоретически можно, но чаще всего пишут так, что лучше б на jQuery.


                          В React на jsx стоит писать только вывод html.

                          Бесспорно. Проблема в том, что «лучшие практики» это не «практики по умолчанию»:)

                      • 0

                        Наоборот! Хочется конвертнуть CoffeeScript — JS? Легко! На ClojureScript вообще можно вытворять чудеса — готовим перевод статьи с практическим примером.


                        А вот конвертора Angular-React я что-то не припомню :)

      • +5
        Еще один момент, который нужно учитывать:
        (() => { return this.foo }).call({foo:1})
        // => undefined
        (function () { return this.foo }).call({foo:1})
        // => 1
        
        • +6
          Это фича, а не баг. Чтобы не было таких костылей: var self = this;
          • +21
            это даже by design — стрелочные функции не создают свой this как раз, чтобы не было все этих self, that, thi$, _this.
            • +6
              Видимо кто-то меня не понял :) Я хотел обратить внимание на то, что стрелочные функции — это не сахар для function () {}.bind(this), как некоторые думают, а отдельные сущности с собственными static and runtime semantics.
              • +1
                Ну да, так и есть. Почему кто-то заминусовал — загадка.
            • +3
              Я в курсе, что это фича, это не значит что такое поведение не нужно иметь в виду.
            • 0

              Строго говоря, первая строка вообще выкинет ошибку, так как this тут будет undefined, вероятно.
              Хотя, рассматривать стрелочную функцию без родительского контекста некорректно, да.

              • 0
                Не выкинет в известных мне окружениях, в браузере например, в global scope this == window
                • 0
                  При «use strict» this не будет равен window.
                  • 0
                    Ухты… неожиданно. Но стрелочных функций это не должно касаться
                • +1
                  http://www.ecma-international.org/ecma-262/6.0/#sec-lexical-environments
                  A global environment is a Lexical Environment which does not have an outer environment. The global environment’s outer environment reference is null. A global environment’s EnvironmentRecord may be prepopulated with identifier bindings and includes an associated global object whose properties provide some of the global environment’s identifier bindings. This global object is the value of a global environment’s this binding. As ECMAScript code is executed, additional properties may be added to the global object and the initial properties may be modified.

                  То есть this равный undefined по стандарту невозможен.
                • +1
                  Тогда и про arguments стоит тоже упомянуть. А вообще, таким людям, которые использует стрелочные функции и не знает об этих особенностях, лучше поискать себя в другой области.
                  • 0
                    какой смысл использовать call в ES2015?
                    • 0
                      В большинстве случаев rest+spread+arrow functions позволяют избежать традиционных для es5 паттернов с bind, call и apply, но иногда нужно контекст передать.
                  • +3
                    Ну, порядок объявления, это очень спорно (да и большинство код-стайлов запрещают это) и пример странный, ведь можно просто:
                    export const sum = (a, b) => a + b;
                    

                    (хотя сам объявляю через function, читается легче и подсветка, да)

                    Ещё можно добавить пункт «Читабельность callstack'а при профайлинге/ошибке»
                    • +7
                      Прекрасно. Хипстеры в своем репертуаре — ломанулись использовать новые «крутые» штуки вместо «некрутых» старых, но забыли разобраться в том, что это на самом деле разные вещи.
                      • 0
                        А мне вот лично не хватает именованных стрелочных функций
                        Именованные функции очень упрощают отладку
                        • 0
                          Ни разу не сталкивался с ситуацией, когда имя у функции упрощало бы отладку. Можно пример?
                          • 0

                            В стектрейсе приятно видеть осмысленное имя функции.

                            • 0
                              Ясно. В хроме с этим проблем нет (месяца два примерно).
                              image

                              Еще пример:
                              image

                              Но, повторюсь, так только в хроме.
                              • +1
                                Не, проблема правильно выглядит так (и теперь даже хуже):

                                Код курильщика и здорового человека
                                <script>
                                	(function no() {
                                		const exec = (fn) => fn();
                                		const error = () => {throw ':('};
                                		const queue = (fn) => fn()
                                		queue(() => exec(error));
                                	})();
                                </script>
                                <script>
                                	(function yes() {
                                		const exec = (fn) => fn();
                                		const error = () => {throw ':)'};
                                		const queue = (fn) => fn()
                                
                                		queue(function worker() {
                                			exec(error)
                                		});
                                	})();
                                </script>

                                • 0

                                  Ну так у вас анонимная функция же (стрелочная) в первом примере и не анонимная во втором. Причем даже в этом случае хром не пишет в стеке anonymous function, пишется имя функции по стеку выше.


                                  Теперь сравните с этим


                                  (function yes() {
                                      const exec = (fn) => fn();
                                      const error = () => {throw ':('};
                                      const queue = (fn) => fn()
                                  
                                      queue(function() {
                                          exec(error)
                                      });
                                  })();
                                  • 0
                                    Так мы об это и пишем, что во втором случае стек читается лучше, а в первом нет, даже хуже, вводит в заблуждение, раньше такого не было, например FF в этом же тесте напишет `anonymous`, что абсолютно правильно.
                                • 0

                                  Скажем, не в хроме, а в стандарте так — когда кладем анонимную функцию в переменную, ее name становится таким же, как имя переменной. ЕМНИП, аналогично, когда ее кладем в свойство объекта. В V8 это реализовано, в остальных — не помню.


                                  Но когда мы пишем arr.map((val) => val.someProperty * 2), она так и остается анонимной.

                          • +31
                            Почему я все еще использую молоток вместо отвертки:
                            1. Ясность намерений. Когда смотришь на человека с молотком, абсолютно понятны его намерения. Не возникает вопросов, в какую же сторону он будет крутить.
                            3. Нужен всего лишь один молоток для всех видов шлицов. Очень удобно.

                            • –8
                              +1
                              Мне сразу это показалось черти-чем.

                              Странная цель написать меньше строк кода в ущерб читаемости.
                              А добавляется еще и бажность.
                              • +5
                                А добавляется еще и бажность.

                                Если не уметь пользоваться — то да.


                                в ущерб читаемости.

                                Спорно. Мне легче понять такое


                                Rx.Observable.fromEvent(worker, 'message')
                                    .map(ev => ev.data * 10)
                                    .buffer(Rx.Observable.interval(500))
                                    .where(x => x.length > 0)
                                    .map(x => x.length);

                                Чем такое


                                Rx.Observable.fromEvent(worker, 'message')
                                    .map(function (ev) { return ev.data * 1; })
                                    .buffer(Rx.Observable.interval(500))
                                    .where(function (x) { return x.length > 0; })
                                    .map(function (x) { return x.length; });
                                • +1

                                  Автор оригинала предлагает как раз первый вариант.

                                  • –6
                                    > Если не уметь пользоваться — то да.

                                    Я не пользовался. Сужу по статье.

                                    > Спорно. Мне легче понять такое

                                    Это какие-то анемичные функции.

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

                                        Я как раз читал, о чем и указал…
                                        В статье показана «несовместимость» с обычными функциями.
                                        Это только добавляет сложности.
                                        Наплодили сущностей.

                                        П.С.
                                        Я например использую goto в PHP и ничего страшного.
                                    • 0
                                      полностью согласен, для анонимных функций стрелочная запись является пожалуй самой удобной

                                      но как я понял, автор разбирает случай объявления глобальных функций внутри модуля
                                  • –1
                                    export {
                                    createCart,
                                    addItemToCart,
                                    removeItemFromCart,
                                    cartSubTotal,
                                    cartTotal,
                                    saveCart,
                                    clearCart,
                                    }

                                    Задачка из разряда «найдите лишнее слово». Подсказка: используйте принцип единой ответственности.
                                    • –10
                                      Спасибо за перевод!
                                      Школота прочитает, вдохновится, и JavaScript НЕ постигнет участь Perl!
                                      • +10
                                        Данный код вызовет ошибку:

                                        > sayHelloTo(‘Bill’);
                                        > const sayHelloTo = (name) => `Hello ${name}

                                        (сдерживает себя, чтоб не начать ругаться матом)

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


                                        Спорно, мягко говоря. Мне, например, намного удобней, когда сначала определены термины, а потом операции над ними.

                                        Мне кажется, что «всплывание» объявлений — это злобное зло, за которое надо бить линейкой по рукам, хотя бы за то, что вот такой код сработает:

                                        (function() {
                                          doFoo('bar');
                                          return;
                                          function doFoo(a) { console.log(a); }
                                        })();
                                        


                                        А представьте теперь, если у вас использование и объявление разнесено например, на 100 строк. И так несколько раз.
                                        • –5

                                          Рекомендую вам всё же не заниматься BDSM с канцелярскими предметами, а присмотреться к довольно неплохому принципу "сначала пишем, что делаем, а потом уже — как".

                                          • 0
                                            +1000. Я постоянно откладываю написания кода:) Потому, что правильные идеи не приходят следом одна за другой. Ну если только к гениям.
                                            • +1
                                              Вспомните школу. В любой задаче — сначала «дано», потом «решение», не наоборот.
                                              • –1

                                                Вы ещё детский сад вспомните. Открываем книгу — оглавление в начале, а не в конце. Открываем любой сайт — меню сверху или слева, а не снизу и справа.


                                                https://ru.wikipedia.org/wiki/Структурное_программирование#.D0.9C.D0.B5.D1.82.D0.BE.D0.B4_.C2.AB.D1.81.D0.B2.D0.B5.D1.80.D1.85.D1.83_.D0.B2.D0.BD.D0.B8.D0.B7.C2.BB

                                                • +2
                                                  Метод «сверху вниз» говорит о порядке декомпозиции — от общего к частному, а не о порядке расположения кода в файле. Если же мы говорим о разработке настоящего приложения, то его код будет разбит на отдельные модули, для которых расположение «ниже» или «выше» относительно друг друга не имеет смысла. Однако, вы когда-нибудь видели, чтобы инструкции import или using были после кода?
                                                  • 0
                                                    Метод «сверху вниз» говорит о порядке декомпозиции — от общего к частному, а не о порядке расположения кода в файле.

                                                    О порядке написания кода.


                                                    код будет разбит на отдельные модули

                                                    Каждую функцию в отдельный модуль?


                                                    Однако, вы когда-нибудь видели, чтобы инструкции import или using были после кода?

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

                                                    • +1
                                                      Каждую функцию в отдельный модуль?

                                                      Вы удивитесь, но так действительно многие делают.

                                                      В каком порядке их предложите объявлять?

                                                      Порядок объявлений не должен играть роли, в отличие от порядка инструкций. К сожалению, в JS разница между этими понятиями размыта, поэтому объявлять функции через const или var нужно с осторожностью.
                                            • 0
                                              Всплытие как раз таки и было сделано для того, чтобы не нужно было пролистывать 100 строк кода, чтобы понять что происходит в файле.
                                              • +3
                                                Как же сложно любить людей, которые активно используют хойстинг в своих js-творениях. Правда ведь, это абсолютно флибустьерская фича, даже jshint на нее ругается.
                                                • –1
                                                  Погодите, ведь хойстинг это часть стандарта и игнорировать его — тоже неверно. Самый яркий пример — сносить стандартные методы, типа различных проверок isArray() и им подобных, удобнее вниз файла. Например у Вас есть длинный класс с кучей методов и, если снести такие проверки вниз, то файл становиться читабельнее, потому как есть методы и свойства, описывающее логику и предназначение класса, которые, будучи вынесены выше, помогут быстрее понять суть.
                                                  • +1
                                                    Не все, что является частью стандарта, необходимо использовать.
                                                    Наглядный пример — особое поведение == (https://dorey.github.io/JavaScript-Equality-Table/)
                                                    Ввиду чего зачастую предпочитают использовать ===
                                                    • +1
                                                      Я и не говорил, что его необходимо использовать, но необходимо понимать, как это работает и быть способным это применить к месту.

                                                      Полностью согласен с примером о строгом сравнении.
                                                      • +2

                                                        А я вот не согласен, нестрого сравнивать с null — куда удобнее, чем строго сравнивать с undefined, а потом с null.

                                                        • +1
                                                          В таком случае стоит использовать Boolean
                                                          • 0

                                                            И каким образом вам тут поможет Boolean?

                                                            • +1
                                                              let a;
                                                              console.log(Boolean(a)) // false;
                                                              a = null;
                                                              console.log(Boolean(a)) // false;
                                                              
                                                              • 0
                                                                a = 0
                                                                console.log(Boolean(a)) // false;
                                                                • 0
                                                                  А разве это всегда плохо?
                                                                  • +1

                                                                    Это, очевидно, не то, что требуется.

                                                          • 0
                                                            undefined подставляет сам компилятор.
                                                • 0
                                                  Имхо, для функций, которые являются «мясом» для данного кода — самое место внизу. Т.е. я предпочитаю структуру кода в виде блоков: объявления, внешний интерфейс (если есть), инициализация, рабочий код, внутреннее API.

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

                                                  PS В различных языках блоки могут сливаться или видоизменяться (в Java — объявления + инициализация переменных класса, объявления + инициализация переменных объекта, конструкторы, паблик API, наследуемое API, приватное API).
                                                • 0

                                                  Вы правда изучали JavaScript в 90-х годах?

                                                  • 0
                                                    Автор написал вначале статьи, что это лишь перевод
                                                  • +6
                                                    1. Читаемость кода всегда выжнее скорости и краткости, так что я согласен.
                                                    2. А это — торба. Использование функций до объявления — антипаттерн. Это та фича языка, которая должна уйти следом за ``with``. Да, это было удобно когда мы говнокодили тысячи строк в одном файле, но сейчас другое время.
                                                    • –3
                                                      eslint говорит что формат функций вида
                                                      function fnName () {}
                                                      
                                                      слишком стар, надо использовать:
                                                      const fnName = function () {}
                                                      


                                                      И я пока склоняюсь ко второму варианту.
                                                      • 0
                                                        объясните новичку, чем различаются эти два формата?
                                                        function fn1 () {}
                                                        var fn2 = function () {}
                                                        


                                                        Мое ограниченное понимание таково:
                                                        1) у fn1 есть имя, а fn2 — анонимная. как это используется и на что влияет, я не очень понимаю
                                                        2) fn1 можно вызвать до объявления, а fn2 — выдаст undefined is not a function (если с const — то и вовсе ошибку при обращении к переменной)
                                                        • 0
                                                          можно почитать например
                                                          https://www.sitepoint.com/function-expressions-vs-declarations/
                                                          там объясняется разница между такими видами объявлений.
                                                          • –1
                                                            Я знаю разницу между ними. И т.к. я стараюсь разрабатывать соблюдая правила, у меня методы не вызываются до их определения. И я не новичек...(
                                                            • 0
                                                              нене, это я новичок и прошу чтобы объяснили мне
                                                            • +4
                                                              у fn1 есть имя, а fn2 — анонимная.

                                                              Не совсем, к ней можно обратиться по имени и у неё есть поле «name», так что не анонимная
                                                              fn2.name // => "fn2"
                                                              

                                                              Разница в том, что первый вариант — это function declaration, когда код будет выполняться, сначала будут созданы все функции объявленные таким образом в текущем scope а потом уже будут выполняться выражения.
                                                              Второй вариант — это function expression, в этом случае функция создается в момент выполнения выражения и является его значением.
                                                              Эти варианты по разному разбираются парсером и имеют разную семантику.
                                                              Чтоб прочувствовать разницу, поиграйтесь с этим кодом в консоли:
                                                              !function t() { console.log('t') }() // immediate function invocation
                                                              function t() { console.log('t') }() // throws a SyntaxError
                                                              
                                                              • 0
                                                                про поле name вообще сюрприз — спасибо большое
                                                          • +1
                                                            Я согласен с вашим пониманием читаемости кода, но не совсем согласен с вашим пониманием самого кода.
                                                            В ваших примерах вы упорно сравниваете function declaraion (function a() {}) с function expression (var a = function() {}).
                                                            Точно так же нельзя сделать так:
                                                            a();
                                                            var a = function() {
                                                              console.log('Hello');
                                                            }
                                                            

                                                            Я думаю, большинство итак знает почему, но, все же, поясню:
                                                            перед запуском кода браузер добавит переменную «a» в область видимости, она станет доступна из любой части кода (да-да, в отличие от const), но значение ей не присвоит и мы получим TypeError: not a function. Вывод: делает невозможным вызов функции до описания отнюдь не es2015, а сам способ объявления.
                                                            • +1
                                                              Взгляните на это:

                                                              const maxNumberOfItemsInCart = ...;

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


                                                              А если руководствоваться простым и вменяемым правилом именования функций, согласно которым название функции должно быть глаголом, подобных проблем не будет. getMaxNumberOfItemsInCart/evalMaxNumberOfItemsInCart и т.п.
                                                              • +2
                                                                Стрелочные функции целесообразно использовать в конструкциях типа array.forEach( item => {} );
                                                                Каждому инструменту своя область применения, иначе это уже похоже на «откручивание гайки молотком».
                                                                • –2
                                                                  По-моему стрелочная функция выглядит ужасно и не понимаю восторга автора по отношению к ней. Да, меньше кода, но зачем? Читаемость кода всегда была и будет на первом месте.
                                                                  • 0

                                                                    У стрелочных функций другая семантика.

                                                                    • 0
                                                                      У стрелочных функций сохраняется контекст this, то есть это не просто те же функции, только пишутся по другому
                                                                      Так же они сокращают код, когда надо всего лишь сделать
                                                                      [' aa ', ' bb '].map(a => a.trim()) // ['aa', 'bb']
                                                                      

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

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