9 профессиональных приемов для крутого программирования на JavaScript в 2019 году

9 профессиональных приемов для крутого программирования на JavaScript в 2019 году

От автора: еще один год закончился, и JavaScript постоянно меняется. Тем не менее, есть для JavaScript профессиональные приемы программирования, которые помогут вам писать чистый и эффективный код, который масштабируется даже (или, может быть, особенно?) в 2019 году. Ниже приведен список из 9 практических советов, которые сделают вас лучшим разработчиком.

1. async / await

Если вы все еще не выбрались из ада обратных вызова, то пора оставить старый код в 2014 году. Просто не используйте обратные вызовы, за исключением случаев, когда это абсолютно необходимо, например, требуется библиотекой или по соображениям производительности. Promises хороши, но их немного неудобно использовать, если ваша кодовая база становится больше. Моим решением в настоящее время является async / await, что делает код намного чище. Фактически, вы можете выполнять await для любого Promise в JavaScript, если библиотека, которую вы используете, возвращает Promise, просто ожидайте его. На самом деле, async / await — это просто синтаксический сахар вокруг Promise. Чтобы код работал, вам нужно всего лишь добавить перед функцией ключевое слово async. Вот простой пример:

async function getData() { const result = await axios.get('https://dube.io/service/ping') const data = result.data console.log('data', data) return data
} getData()

Обратите внимание, что выполнять await на верхнем уровне невозможно, вы можете только вызвать функцию async. async / await был представлен в ES2017, так что не забудьте перенести свой код.

2. Поток управления async

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

for…of

Допустим, у нас на странице есть несколько покемонов, и мы должны получить подробную информацию о них. Мы не хотим ждать завершения всех вызовов, особенно когда мы не знаем, сколько их, но мы хотим обновить наборы данных, как только получим что-то взамен. Мы можем использовать for…of для перебора массива и выполнения кода async внутри блока, выполнение не будет остановлено до тех пор, пока каждый вызов не будет успешным. Важно отметить, что могут возникать проблемные места производительности, если вы делаете что-то подобное в коде, но этот прием полезно иметь в вашем наборе инструментов. Вот пример:

import axios from 'axios' let myData = [{id: 0}, {id: 1}, {id: 2}, {id: 3}] async function fetchData(dataSet) { for(entry of dataSet) { const result = await axios.get(`https://ironhack-pokeapi.herokuapp.com/pokemon/${entry.id}`) const newData = result.data updateData(newData) console.log(myData) }
} function updateData(newData) { myData = myData.map(el => { if(el.id === newData.id) return newData return el })
} fetchData(myData)

Эти примеры на самом деле работают, не стесняйтесь копировать и вставлять их в свой любимый sandbox кода

Promise.all

Что если вы хотите получить всех покемонов параллельно? Поскольку вы можете выполнять await для всех Promises, просто используйте Promise.all:

import axios from 'axios' let myData = [{id: 0}, {id: 1}, {id: 2}, {id: 3}] async function fetchData(dataSet) { const pokemonPromises = dataSet.map(entry => { return axios.get(`https://ironhack-pokeapi.herokuapp.com/pokemon/${entry.id}`) }) const results = await Promise.all(pokemonPromises) results.forEach(result => { updateData(result.data) }) console.log(myData) } function updateData(newData) { myData = myData.map(el => { if(el.id === newData.id) return newData return el })
} fetchData(myData)

for…of и Promise.all были введены с ES6 +, так что убедитесь, что ваш код транспилируется.

3. Деструктурирование и значения по умолчанию

Давайте вернемся к нашему предыдущему примеру, где мы делаем следующее:

const result = axios.get(`https://ironhack-pokeapi.herokuapp.com/pokemon/${entry.id}`) const data = result.data

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

const { data } = await axios.get(...)

Мы сэкономили одну строку кода! Ура! Вы также можете переименовать переменную:

const { data: newData } = await axios.get(...)

Еще один полезный трюк — задать значения по умолчанию при деструктурировании. Это гарантирует, что вы никогда не получите в конечном итоге undefined, и вам не нужно проверять переменные вручную.

const { id = 5 } = {} console.log(id) // 5

Эти приемы также можно использовать с параметрами функции, например:

function calculate({operands = [1, 2], type = 'addition'} = {}) { return operands.reduce((acc, val) => { switch(type) { case 'addition': return acc + val case 'subtraction': return acc - val case 'multiplication': return acc * val case 'division': return acc / val } }, ['addition', 'subtraction'].includes(type) ? 0 : 1)
} console.log(calculate()) // 3
console.log(calculate({type: 'division'})) // 0.5
console.log(calculate({operands: [2, 3, 4], type: 'multiplication'})) // 24

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

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

4. Истинные и ложные значения

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

if(myBool === true) { console.log(...)
} // OR if(myString.length > 0) { console.log(...)
} // OR if(isNaN(myNumber)) { console.log(...)
}

Все это можно сократить до:

if(myBool) { console.log(...)
} // OR if(myString) { console.log(...)
} // OR if(!myNumber) { console.log(...)
}

Чтобы по воспользоваться этими операторами, вы должны понять, что такое истинные и ложные значения. Вот небольшой обзор:

Ложные

строки длиной 0

число 0

false

undefined

null

NaN

Истинные

пустые массивы

пустые элементы

все остальное

Обратите внимание, что при проверке истинности / ложности значений нет явного сравнения, что приравнивается к проверке с двойными знаками равенства ==, а не с тройными ===. В целом, это ведет себя так же, но есть определенные ситуации, в которых вы можете получить ошибку. Для меня это произошло в случае значения 0.

5. Логические и троичные операторы

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

Логические операторы

Логические операторы в основном объединяют два выражения и возвращают либо true, либо false, либо соответствующее значение, и представляются через &&, что означает «и», а также ||, что означает «или». Давайте рассмотрим примеры:

console.log(true && true) // true console.log(false && true) // false console.log(true && false) // false console.log(false && false) // false console.log(true || true) // true console.log(true || false) // true console.log(false || true) // true console.log(false || false) // false

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

&&: Возвращается первое ложное значение, если его нет, возвращается последнее истинное значение.

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

console.log(0 && {a: 1}) // 0 console.log(false && 'a') // false console.log('2' && 5) // 5 console.log([] || false) // [] console.log(NaN || null) // null console.log(true || 'a') // true

Тернарный оператор

Тернарный оператор очень похож на логический, но состоит из трех частей:

Сравнение, которое будет либо ложным, либо истинным

Первое возвращаемое значение, если сравнение истинно

Второе возвращаемое значение, если сравнение ложно

Вот пример:

const lang = 'German' console.log(lang === 'German' ? 'Hallo' : 'Hello') // Hallo console.log(lang ? 'Ja' : 'Yes') // Ja console.log(lang === 'French' ? 'Bon soir' : 'Good evening') // Good evening

6. Опциональные последовательности

Была ли у вас когда-нибудь проблема доступа к вложенному свойству объекта, когда вы даже не знали, существует ли объект или одно из его под-свойств? Вы, вероятно, в конечном итоге получали что-то вроде этого:

let data
if(myObj && myObj.firstProp && myObj.firstProp.secondProp && myObj.firstProp.secondProp.actualData) data = myObj.firstProp.secondProp.actualData

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

const data = myObj?.firstProp?.secondProp?.actualData

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

В настоящее время опциональная последовательность не является частью официальной спецификации, но находится на этапе 1 в качестве экспериментальной функции. Чтобы использовать ее, вы должны добавить в babelrc @babel/plugin-proposal-optional-chaining.

7. Свойства класса и привязка

Привязка функций в JavaScript — обычная задача. С введением функций стрелок в спецификации ES6 у нас теперь есть способ автоматически связывать функции с контекстом объявления — очень полезный и широко используемый среди разработчиков JavaScript метод. Когда классы были представлены впервые, вы больше не могли использовать функции стрелок, потому что методы класса должны быть объявлены определенным образом. Нам нужно было связывать функции в другом месте, например, в конструкторе (наилучшая практика для React.js). Меня всегда беспокоил рабочий процесс: сначала мы определяли методы класса, а затем связывали их, через некоторое время это просто кажется нерациональным. С синтаксисом свойства класса мы можем снова использовать функции стрелок и получить преимущества автоматической привязки. Функция стрелки теперь может использоваться внутри класса. Вот пример с привязкой _increaseCount:

class Counter extends React.Component { constructor(props) { super(props) this.state = { count: 0 } } render() { return( <div> <h1>{this.state.count}</h1> <button onClick={this._increaseCount}>Increase Count</button> </div> ) } _increaseCount = () => { this.setState({ count: this.state.count + 1 }) }
}

В настоящее время свойства класса не являются частью официальной спецификации, но находятся на стадии 3 в качестве экспериментальной функции. Чтобы использовать их, вы должны добавить в babelrc @babel/plugin-proposal-class-properties.

8. Используйте parcel

Как front-end разработчик, вы почти наверняка сталкивались с пакетированием и переносом кода. Фактически в течение длительного времени стандартом для этого был webpack. Я впервые использовал webpack в версии 1, что было утомительно. Работая со всеми вариантами конфигурации, я потратил бесчисленные часы, пытаясь настроить и запустить пакет. Если бы я мог, я бы никогда не трогал его снова, чтобы ничего не сломать. Пару месяцев назад мне попался parcel, который стал настоящим облегчением. Он делает практически все из коробки, но при этом дает вам возможность изменить его, если это необходимо. Он также поддерживает систему плагинов, похожую на webpack или babel, и невероятно быстр. Если вы не знакомы с parcel, я определенно советую вам попробовать его!

9. Пишите больше кода самостоятельно

Это хорошая практика. У меня было много разных дискуссий по этому поводу. Даже для CSS многие люди склонны использовать библиотеку компонентов, такую как bootstrap. Что касается JavaScript, я все еще вижу людей, использующих jQuery и небольшие библиотеки для валидации, слайдеров и так далее. Хотя имеет смысл использовать библиотеки, я настоятельно рекомендую писать больше кода самостоятельно, а не слепо устанавливать npm-пакеты. Когда есть большие библиотеки (или даже фреймворки), которые собирает целая команда, например moment.js или response -datepicker, не имеет смысла пытаться кодировать это самостоятельно. Тем не менее, вы можете написать большую часть кода, который используете сами. Это даст вам три основных преимущества:

Вы точно знаете, что происходит в вашем коде

В какой-то момент вы начнете действительно понимать программирование и как все работает под капотом

Вы предотвращаете раздутие кода

В начале проще использовать пакет npm. На самостоятельную реализацию некоторых функций уйдет больше времени. Но что, если пакет на самом деле не работает должным образом, и вам нужно сменить его на другой, потратив еще больше времени на чтение того, как настроен их API. Реализуя это самостоятельно, вы можете адаптировать его на сто процентов к вашему сценарию использования.

Автор: Lukas Gisder-Dubé

Источник: https://levelup.gitconnected.com/

Редакция: Команда webformyself.