HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-03-10
1 <p>Теги: const, javascript, return, case, break, тернарный оператор, функция-инициализатор, return из switch, redux-редьюсер</p>
1 <p>Теги: const, javascript, return, case, break, тернарный оператор, функция-инициализатор, return из switch, redux-редьюсер</p>
2 <p>Рассмотрим, как сделать код на JavaScript короче и понятнее, умело расставляя return в нужных местах.</p>
2 <p>Рассмотрим, как сделать код на JavaScript короче и понятнее, умело расставляя return в нужных местах.</p>
3 <h3>else после return (не нужен)</h3>
3 <h3>else после return (не нужен)</h3>
4 <p>Первый трюк - вынесение одной из ветвей if / else на уровень выше. Для примера возьмём функцию сравнения массивов:</p>
4 <p>Первый трюк - вынесение одной из ветвей if / else на уровень выше. Для примера возьмём функцию сравнения массивов:</p>
5 function iaArrayEqual(arr1, arr2) { if (arr1.length !== arr2.length) { return false; } else { return arr1.every((el, i) =&gt; el === arr2[i]); } }<p>Если при выполнении мы попали в первый if, то дальше и так уже не пойдём, потому что вышли из функции. Значит, else можно просто убрать:</p>
5 function iaArrayEqual(arr1, arr2) { if (arr1.length !== arr2.length) { return false; } else { return arr1.every((el, i) =&gt; el === arr2[i]); } }<p>Если при выполнении мы попали в первый if, то дальше и так уже не пойдём, потому что вышли из функции. Значит, else можно просто убрать:</p>
6 function iaArrayEqual(arr) { if (array.length === 0) { return false; } return arr1.every((el, i) =&gt; el === arr2[i]); }<p>Мы сделали код не только короче, но и понятнее: сначала обрабатываем специальный случай, потом, если не получилось, - переходим к основной логике. Даже просто думать про алгоритмы в таких терминах уже полезно. Приятный бонус: теперь более частый и важный код стоит левее, так что его проще заметить и прочитать.</p>
6 function iaArrayEqual(arr) { if (array.length === 0) { return false; } return arr1.every((el, i) =&gt; el === arr2[i]); }<p>Мы сделали код не только короче, но и понятнее: сначала обрабатываем специальный случай, потом, если не получилось, - переходим к основной логике. Даже просто думать про алгоритмы в таких терминах уже полезно. Приятный бонус: теперь более частый и важный код стоит левее, так что его проще заметить и прочитать.</p>
7 <p>Ещё круче этот метод работает, когда особых случаев несколько. Посмотрите сами на примере несложного реакт-компонента:</p>
7 <p>Ещё круче этот метод работает, когда особых случаев несколько. Посмотрите сами на примере несложного реакт-компонента:</p>
8 const UserList = ({ users, isError }) =&gt; { if (users.length === 0) { return &lt;Empty /&gt;; } else { if (!isError) { return &lt;Users users={users} /&gt;; } else { return &lt;Error /&gt;; } } }; const UserList2 = ({ users, isError }) =&gt; { if (users.length === 0) { return &lt;Empty /&gt;; } if (isError) { return &lt;Error /&gt; } return &lt;Users users={this.users} /&gt;; };<h3>Функционалный инициализатор</h3>
8 const UserList = ({ users, isError }) =&gt; { if (users.length === 0) { return &lt;Empty /&gt;; } else { if (!isError) { return &lt;Users users={users} /&gt;; } else { return &lt;Error /&gt;; } } }; const UserList2 = ({ users, isError }) =&gt; { if (users.length === 0) { return &lt;Empty /&gt;; } if (isError) { return &lt;Error /&gt; } return &lt;Users users={this.users} /&gt;; };<h3>Функционалный инициализатор</h3>
9 <p>Второй трюк - вынести сложную логику инициализации в функцию. Тернарный оператор помогает инициализирвать переменную одним из двух значений по условию: const userName = user ? user.name : 'unknown';. Но как только добавляется ветвь, начинаются проблемы - в лучшем случае это выглядит так:</p>
9 <p>Второй трюк - вынести сложную логику инициализации в функцию. Тернарный оператор помогает инициализирвать переменную одним из двух значений по условию: const userName = user ? user.name : 'unknown';. Но как только добавляется ветвь, начинаются проблемы - в лучшем случае это выглядит так:</p>
10 let userName = 'unknown'; if (user) { userName = user.name } else if (config.defaultUser) { userName = config.defaultUser.name }<p>Из плохого: мы отказались от const ради единственного присваивания, но потеряли его защиту во всём блоке. Кроме того, теперь при чтении кода мы в первую очередь увидим самое запасное значение переменной. Для таких случаев мне нравится заводить функцию-инициализатор (хотите показаться чуть умнее - используйте слово<em>фабрика</em>):</p>
10 let userName = 'unknown'; if (user) { userName = user.name } else if (config.defaultUser) { userName = config.defaultUser.name }<p>Из плохого: мы отказались от const ради единственного присваивания, но потеряли его защиту во всём блоке. Кроме того, теперь при чтении кода мы в первую очередь увидим самое запасное значение переменной. Для таких случаев мне нравится заводить функцию-инициализатор (хотите показаться чуть умнее - используйте слово<em>фабрика</em>):</p>
11 const getUserName = (user, defaultUser) =&gt; { if (user) return user.name; if (defaultUser) return defaultUser.name; return 'unknown'; }; const userName = getUserName(user, defaultUser);<p>Обратите внимание, что я использую первый трюк, но "неправильно" - специальные случаи обрабатываются внизу. В данном случае это логичнее - мы падаем вниз, пока одна из страховок не сработает.</p>
11 const getUserName = (user, defaultUser) =&gt; { if (user) return user.name; if (defaultUser) return defaultUser.name; return 'unknown'; }; const userName = getUserName(user, defaultUser);<p>Обратите внимание, что я использую первый трюк, но "неправильно" - специальные случаи обрабатываются внизу. В данном случае это логичнее - мы падаем вниз, пока одна из страховок не сработает.</p>
12 <h3>return из switch</h3>
12 <h3>return из switch</h3>
13 <p>Наконец, ещё одно применение похожего трюка. У конструкции switch симпатичная задумка, но странноватый синтаксис - в ветках нет блоков, и код выполняется от первого подходящего case до ближайшего break. В коде самого частого кейса получается больше синтаксиса, чем логики:</p>
13 <p>Наконец, ещё одно применение похожего трюка. У конструкции switch симпатичная задумка, но странноватый синтаксис - в ветках нет блоков, и код выполняется от первого подходящего case до ближайшего break. В коде самого частого кейса получается больше синтаксиса, чем логики:</p>
14 let msg = 'Something happened'; switch (event) { case 'err': msg = 'An error occurred'; break; case 'fire': msg = 'There\'s a fire'; break; case 'ready': msg = 'All set and ready to roll'; break; } return msg;<p>Если вы внимательно следили за первыми двумя трюками, то легко примените их к этому случаю:</p>
14 let msg = 'Something happened'; switch (event) { case 'err': msg = 'An error occurred'; break; case 'fire': msg = 'There\'s a fire'; break; case 'ready': msg = 'All set and ready to roll'; break; } return msg;<p>Если вы внимательно следили за первыми двумя трюками, то легко примените их к этому случаю:</p>
15 function makeMsg(event) { switch (event) { case 'err': return 'An error occurred'; case 'fire': return 'There\'s a fire'; case 'ready': return 'All set and ready to roll'; } return 'Unknown'; } const msg = makeMsg(event);<p>Кстати, именно так обычно записывают redux-редьюсеры. Если зайти ещё дальше, весь switch вообще можно превратить из кода в конфигурацию:</p>
15 function makeMsg(event) { switch (event) { case 'err': return 'An error occurred'; case 'fire': return 'There\'s a fire'; case 'ready': return 'All set and ready to roll'; } return 'Unknown'; } const msg = makeMsg(event);<p>Кстати, именно так обычно записывают redux-редьюсеры. Если зайти ещё дальше, весь switch вообще можно превратить из кода в конфигурацию:</p>
16 const MESSAGES = { 'err': 'An error occurred', 'fire': 'There\'s a fire', 'ready': 'All set and ready to roll', }; const DEFAULT_MESSAGE = 'Unknown'; const makeMsg = event =&gt; MESSAGES[event] || DEFAULT_MSG;<p>Впрочем, мне такой вариант не очень нравится - если в одном из случаев нужно добавить специальную логику, у нас проблемы.</p>
16 const MESSAGES = { 'err': 'An error occurred', 'fire': 'There\'s a fire', 'ready': 'All set and ready to roll', }; const DEFAULT_MESSAGE = 'Unknown'; const makeMsg = event =&gt; MESSAGES[event] || DEFAULT_MSG;<p>Впрочем, мне такой вариант не очень нравится - если в одном из случаев нужно добавить специальную логику, у нас проблемы.</p>
17 <p>Это мои любимые трюки в области код-стайла - когда я вижу огромный легаси-код с сотней вложенных ветвлений, за которыми стало невозможно уследить ещё лет 10 назад, я начинаю<em>очень аккуратно</em>разбирать его на блоки, выносить специальные случаи и извлекать основную логику - и скоро в нём могут разобраться не только стажеры, но даже и я сам.</p>
17 <p>Это мои любимые трюки в области код-стайла - когда я вижу огромный легаси-код с сотней вложенных ветвлений, за которыми стало невозможно уследить ещё лет 10 назад, я начинаю<em>очень аккуратно</em>разбирать его на блоки, выносить специальные случаи и извлекать основную логику - и скоро в нём могут разобраться не только стажеры, но даже и я сам.</p>
18  
18