5 фич JavaScript, без которых я не мог бы писать код (перевод)

от автора

Доброго времени суток, друзья!

Представляю Вашему вниманию перевод статьи Kent Dodds «5 JavaScript Features I Couldn’t Code Without».

Это мой первый перевод, так что буду рад любым замечаниям.

5 фич JavaScript, без которых я не мог бы писать код

Прежде чем мы начнем, позвольте мне немного рассказать о коде, который я пишу. Почти весь мой код состоит из Javascript, плюс немного HTML и CSS. Я пишу как клиентский, так и серверный JS. Я тестирую свой код. Я создаю и распространяю библиотеки с открытым исходным кодом, которые используются тысячами разработчиков по всему миру. Для фронтенда я использую React, для бэкенда — Express или бессерверные вычисления.

Вот 5 фич JS, без которых я не мог бы писать код. В произвольном порядке. Разумеется, «без которых я не мог бы писать код» — это гипербола. Это фичи, которые мне по-настоящему нравятся и используются мной постоянно.

1. Деструктуризация

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

Вот несколько примеров:

const address = {   city: 'Salt Lake City',   state: 'UT',   zip: 84115,   coords: {     lat: 40.776608,     long: -111.920485,   }, }  // допустим, вы хотите сделать это: const city = address.city const state = address.state const zip = address.zip  // используя деструктуризацию, вы можете сделать так: const {city, state, zip} = address  

Вот как это выглядит в React:

// без деструктуризации: function UserName(props) {   return (     <div>             </div>   ) }  // с использованием деструктуризации: function UserName() {   return (     <div>             </div>   ) }  // с использованием вложенной деструктуризации: function UserName({name: {first, last}}) {   return (     <div>             </div>   ) } 

Эта фича позволяет делать некоторые интересные вещи:

const info = {   title: 'Once Upon a Time',   protagonist: {     name: 'Emma Swan',     enemies: [       {name: 'Regina Mills', title: 'Evil Queen'},       {name: 'Cora Mills', title: 'Queen of Hearts'},       {name: 'Peter Pan', title: `The boy who wouldn't grow up`},       {name: 'Zelena', title: 'The Wicked Witch'},     ],   }, }  // при правильном форматировании вложенная деструктуризация довольно проста, // хотя не все разделяют мое мнение на этот счет const {   title,   protagonist: {     name: name,     enemies: [, , , {title: enemyTitle, name: enemyName}],   }, } = info  console.log(`$ ($) is an enemy to $ in "$5 JavaScript Features I Couldn't Code Without"`) 

2. Модули

Это еще одна фича, которую я использую практически в каждом файле. До того как модули стали частью языка, приходилось использовать странные библиотеки и инструменты для работы с большими проектами. С модулями (и сборщиками, такими как Rollup или Webpack) у нас появилась отличная возможность делиться кодом с другими.

Вот парочка примеров:

// a.js // экспорт function add(a, b) {   return a + b }  const foo = 'bar'  const theAnswer = 42 const theQuestion = 'who knows'     // синтаксис модулей позволяет экспортировать их во время создания, но // мне нравится размещать все "экспорты" в одном месте export default add export {foo, theAnswer, theQuestion}  // b.js // импорт // 1. импортируем модуль import './a'  // 2. импортируем по умолчанию import add from './a'  // 3. импортируем `theAnswer` и `theQuestion` из './a' import {theAnswer, theQuestion} from './a'  // 4. импортируем `theAnswer` и переименовываем его в `fortyTwo` import {theAnswer as fourtyTwo} from './a'  // 5. импортируем `add` (по умолчанию) и `theQuestion` import {default as add, theQuestion} from './a'  // 6. импортируем `add` и `theQuestion` без указания импорта по умолчанию import add,  from './a'     // 7. импортируем все в единое "пространство имен" под названием `allTheThings` import * as allTheThings from './a' 

Если Вы хотите узнать больше о модулях, можете посмотреть мое видео на youtube — «More than you want to know about ES6 Modules».

3. Параметры по умолчанию

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

const bench = {type: 'Piano', adjustable: false} const {legs = 4} = bench // `The bench has $ legs` // -> The bench has 4 legs // bench - скамья, leg - ножка 

Обратите внимание, что у объекта bench нет свойства legs. Без использования синтаксиса параметров по умолчанию значением legs будет undefined.

Вы также можете использовать деструктурирующее присваивание с этой фичей:

const bench = {type: 'Piano', adjustable: false} const {legs: legCount = 4} = bench // `The bench has $ legs` // -> The bench has 4 legs 

Вот как это выглядит в списке параметров:

function getDisplayName(firstName = 'Unknown', lastName = 'Unknown') {   return `$ $` }  // getDisplayName() // -> Unknown Unknown  // getDisplayName('Andrew') // -> Andrew Unknown  // getDisplayName(undefined, 'Yang') // -> Unknown Yang  // getDisplayName('Andrew', 'Yang') // -> Andrew Yang 

Эта фича также позволяет делать некоторые довольно интересные вещи, поскольку значение справа от знака «=» вычисляется только при необходимости. Это означает, что Вы можете использовать ее для проверки наличия обязательных параметров:

function getCandy(   kind = requiredParam('kind'),   size = requiredParam('size'),   upperKind = kind.toUpperCase(),   callback = function noop() {}, ) {   const result = {kind, size, upperKind}   callback(result)   return result }  function requiredParam(argName) {   throw new Error(`$ is required`) }  // getCandy('twix', 'king') // -> {kind: 'twix', size: 'king', upperKind: 'TWIX'} // getCandy('twix') // -> ошибка: 'size is required' 

Некоторые считают этот код слишком сложным. Возможно, они правы. Но понимать, как это работает, очень круто!

О, а Вы заметили, что мы можем использовать предыдущие аргументы как часть параметров по умолчанию для следующих аргументов (как в случае с upperKind)? Здорово, правда?

4. Стрелочные функции

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

Вот несколько примеров использования стрелочных функций:

const divide = (a, b) => a / b const getFive = () => 5 const identity = i => i const asArray = (...args) => args  // обычно, я не именую стрелочные функции с несколькими аргументами // (в таких случаях я использую обычные функциональные выражения), // но Вы можете их именовать, если хотите: const tryInvoke = (obj, fn, ...args) => {   try {     return obj[fn](...args)   } catch (e) {     return undefined   } }     // для того, чтобы вернуть объект, необходимо заключить его в круглые скобки const getObject = favoriteCandy => ()  // многострочные JSX (расширение JS в React) также должны быть заключены в круглые скобки const MyComponent = () => (   <div>     Hello world! I am a function and I return <strong>JSX!</strong>   </div> ) 

5. Промисы и async/await

JS является однопоточным и построен на системе событий (стеке вызовов). Я большой поклонник разговоров типа Что такое event loop? (с русскими субтитрами). Промисы и async/await являются отличными инструментами для управления этим. Большая часть моего кода является асинхронной и названные инструменты значительно упрощают мою работу. Честно говоря, промисы являются серьезной темой и требуют некоторого «привыкания», но они классные.

Я часто использую async/await в тестах и бэкенде. Вот пример асинхронного теста:

test('Can fill out a form across multiple pages', async () => {   mockSubmitForm.mockResolvedValueOnce({success: true})   const testData = {food: 'test food', drink: 'test drink'}   const {findByLabelText, findByText} = render(<App />)    user.click(await findByText(/fill.*form/i))    user.type(await findByLabelText(/food/i), testData.food)   user.click(await findByText(/next/i))    user.type(await findByLabelText(/drink/i), testData.drink)   user.click(await findByText(/review/i))    expect(await findByLabelText(/food/i)).toHaveTextContent(testData.food)   expect(await findByLabelText(/drink/i)).toHaveTextContent(testData.drink)    user.click(await findByText(/confirm/i, {selector: 'button'}))    expect(mockSubmitForm).toHaveBeenCalledWith(testData)   expect(mockSubmitForm).toHaveBeenCalledTimes(1)    user.click(await findByText(/home/i))    expect(await findByText(/welcome home/i)).toBeInTheDocument() }) 

А вот пример использования async\await в Express:

async function getListItems(req, res) {   const listItems = await listItemsDB.query({ownerId: req.user.id})   res.json({listItems: await expandBookDataMultiple(listItems)}) } 

Любопытно, что я не часто использую async/await в своем React-коде (по крайней мере, напрямую). Так происходит потому, что я стараюсь делать большую часть «асинхронной логики» вне моих компонентов. Поэтому если я, например, делаю что-то асинхронное при вызове useEffect в React, я ограничиваюсь одним вызовом асинхронной функции, поскольку считаю, что с промисами работать легче:

React.useEffect(() => {   getUser().then(     user => setState({status: 'success', error: null, user}),     error => setState({status: 'error', error, user: null}),   ) }, []) 

Советую прочитать статью Anthony Chu «Async/Await in Node».

Заключение

Существует множество других фич, которые я регулярно использую и которые могли бы войти в этот список. Приведенные фичи — мои любимые, к ним я все время обращаюсь. Имеются также некоторые свежие дополнения к языку, которые еще не вошли в мою мышечную память. Сейчас самое время стать JS-разработчиком! Надеюсь, это статья была Вам полезной! Удачи!


ссылка на оригинал статьи https://habr.com/ru/post/483822/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *