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) => 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) => el === arr2[i]); } }<p>Если при выполнении мы попали в первый if, то дальше и так уже не пойдём, потому что вышли из функции. Значит, else можно просто убрать:</p>
6
function iaArrayEqual(arr) { if (array.length === 0) { return false; } return arr1.every((el, i) => el === arr2[i]); }<p>Мы сделали код не только короче, но и понятнее: сначала обрабатываем специальный случай, потом, если не получилось, - переходим к основной логике. Даже просто думать про алгоритмы в таких терминах уже полезно. Приятный бонус: теперь более частый и важный код стоит левее, так что его проще заметить и прочитать.</p>
6
function iaArrayEqual(arr) { if (array.length === 0) { return false; } return arr1.every((el, i) => el === arr2[i]); }<p>Мы сделали код не только короче, но и понятнее: сначала обрабатываем специальный случай, потом, если не получилось, - переходим к основной логике. Даже просто думать про алгоритмы в таких терминах уже полезно. Приятный бонус: теперь более частый и важный код стоит левее, так что его проще заметить и прочитать.</p>
7
<p>Ещё круче этот метод работает, когда особых случаев несколько. Посмотрите сами на примере несложного реакт-компонента:</p>
7
<p>Ещё круче этот метод работает, когда особых случаев несколько. Посмотрите сами на примере несложного реакт-компонента:</p>
8
const UserList = ({ users, isError }) => { if (users.length === 0) { return <Empty />; } else { if (!isError) { return <Users users={users} />; } else { return <Error />; } } }; const UserList2 = ({ users, isError }) => { if (users.length === 0) { return <Empty />; } if (isError) { return <Error /> } return <Users users={this.users} />; };<h3>Функционалный инициализатор</h3>
8
const UserList = ({ users, isError }) => { if (users.length === 0) { return <Empty />; } else { if (!isError) { return <Users users={users} />; } else { return <Error />; } } }; const UserList2 = ({ users, isError }) => { if (users.length === 0) { return <Empty />; } if (isError) { return <Error /> } return <Users users={this.users} />; };<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) => { if (user) return user.name; if (defaultUser) return defaultUser.name; return 'unknown'; }; const userName = getUserName(user, defaultUser);<p>Обратите внимание, что я использую первый трюк, но "неправильно" - специальные случаи обрабатываются внизу. В данном случае это логичнее - мы падаем вниз, пока одна из страховок не сработает.</p>
11
const getUserName = (user, defaultUser) => { 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 => 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 => MESSAGES[event] || DEFAULT_MSG;<p>Впрочем, мне такой вариант не очень нравится - если в одном из случаев нужно добавить специальную логику, у нас проблемы.</p>
17
<p>Это мои любимые трюки в области код-стайла - когда я вижу огромный легаси-код с сотней вложенных ветвлений, за которыми стало невозможно уследить ещё лет 10 назад, я начинаю<em>очень аккуратно</em>разбирать его на блоки, выносить специальные случаи и извлекать основную логику - и скоро в нём могут разобраться не только стажеры, но даже и я сам.</p>
17
<p>Это мои любимые трюки в области код-стайла - когда я вижу огромный легаси-код с сотней вложенных ветвлений, за которыми стало невозможно уследить ещё лет 10 назад, я начинаю<em>очень аккуратно</em>разбирать его на блоки, выносить специальные случаи и извлекать основную логику - и скоро в нём могут разобраться не только стажеры, но даже и я сам.</p>
18
18