Современные функции JavaScript, которые вы должны использовать каждый день для лучшей разработки, и какие проблемы они решают.

Времена, когда JavaScript использовался только для добавления небольшого количества взаимодействия на веб-сайте, давно прошли. Новые стандарты EcmaScript теперь выпускаются каждый год, принося все больше и больше полезных и мощных функций, а JavaScript больше не используется только во Front-End, так как теперь можно также создавать серверную архитектуру, мобильные, настольные или IOT-приложения.

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

Let / Const

С тех пор, как я начал использовать let и const, я больше никогда не использовал ключевое слово var. 'let' было введено как замена 'var'. И let, и const имеют область видимости блока, а var - область видимости функции. Это означает, что если мы, например, инициализируем 'var' внутри цикла for, он также будет доступен за его пределами.

var animals = ['chicken', 'duck', 'cow'];
for (var key in animals) {
 var animal = animals[key];
}
console.log(animal); // cow

Как видите, мы объявили переменную animal внутри цикла, но мы все еще можем получить к ней доступ вне его. Однако, если вместо этого мы будем использовать let, мы получим ошибку Reference, что «animal» не определено.

const animals = ['chicken', 'duck', 'cow'];
for (var key in animals) {
  let animal = animals[key];
}
console.log(animal); // Reference error

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

const animals = ['chicken', 'duck', 'cow'];
let animal
for (var key in animals) {
  animal = animals[key];
}
console.log(animal); // cow

Кроме того, возможно, вы заметили, что в этих примерах я также заменил var animals = [] на const animals = []. Если присвоенное значение не должно изменяться в будущем, полезно использовать «константу». Итак, если вы объявите его с помощью 'var', вы можете изменить его на String, Object, Number и т. Д.

var animals = ['chicken', 'duck', 'cow'];
animals = {
  animal1: 'cow',
  animal2: 'chicken'
}
console.log(animals); // Object {animal1: "cow", animal2: "chicken"}

Однако, если вы присвоите значение «const» и попытаетесь его изменить, вы получите сообщение об ошибке.

const animals = ['chicken', 'duck', 'cow'];
animals = {
  animal1: 'cow',
  animal2: 'chicken'
}
console.log(animals); // SyntaxError: animals is read-only

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

const animals = ['chicken', 'duck', 'cow'];
animals[0] = 'pig';
console.log(animals); // ["pig", "duck", "cow"]

Очень интересная особенность let заключается в том, что каждый раз, когда он объявляется, он создает новую новую привязку для области видимости. Представьте, что вам нужно перебрать какие-то данные, и в каждом цикле вам нужно сделать вызов api, а затем использовать значение индекса из цикла в обратном вызове.

for (var i = 0; i < 5; i++) {
 axios.get(‘https://swapi.co/api/people/1')
 .then(resp => {
 console.log(i); // 5
 })
}

В этом случае console.log всегда будет 5. Это связано с тем, что цикл for не ожидает завершения вызова api, а когда первый ответ возвращается, цикл уже завершен. Вы также можете увидеть это на изображении ниже.

Одно из возможных исправлений для этого - создать закрытие для каждого цикла, чтобы мы могли сохранить индекс цикла для каждого вызова API. Мы можем использовать Immediately Invoked Function Expression (IIFE), которому мы передадим наш индекс. Это функция, которая вызовет себя и сразу же запустится.

К счастью, с let нам этого делать не нужно. Мы можем просто объявить «i» в цикле с ключевым словом «let» вместо «var», и это исправит это для нас.

Шаблонные литералы

Я до сих пор помню, когда, если мне приходилось создавать динамическую разметку, мне приходилось писать много ненужного (но тогда, к сожалению, необходимого) кода, который также был трудно читаемым. Вы только посмотрите на это:

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

let result = `${variable} / ${variable} / ${variable}`
let result = variable + ' / ' + variable + ' / ' + variable

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

Я использую стрелочные функции все время, и, честно говоря, я использую обычное объявление функции только тогда, когда это необходимо. Есть несколько вещей о функциях стрелок, которые очень важно помнить. Во-первых, это тот факт, что стрелочная функция по сравнению с обычными функциями не имеет лексической области видимости. Это означает, что «this» будет относиться к разным объектам в стрелочных и обычных функциях.

function Person (age) {
  this.age = age
  function getAge() {
    console.log('age', this.age) //undefined
    return this.age
  }
  return {
    getAge
  }
}
const Myke = new Person(25);
console.log(Myke.getAge()); // undefined

В этом случае, как мы видим, попытка получить доступ к 'age' в 'this' приведет к ошибке, потому что 'this' больше не относится к объекту 'Person', а относится к самой функции getAge. Раньше нам обычно приходилось присваивать this переменной типа var self = this, а затем использовать ее в обратных вызовах. Однако, если мы воспользуемся стрелочной функцией, мы сможем получить доступ к свойству age.

const getAge = () => {
  console.log('age', this.age) // 25
  return this.age
}

Конечно, я знаю, что мы могли бы просто назначить getAge как свойство непосредственно для объекта, и тогда у нас был бы доступ к «возрасту», но это было сделано только для демонстрационных целей. Стрелочные функции особенно полезны для обратных вызовов и таких функций, как фильтр или карта, при попытке доступа к свойству из внешней области.

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

function vegetables (name, colour) {
  console.log(arguments); // Object {0: "carrot", 1: "orange"}
};
vegetables('carrot', 'orange');

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

const vegetables = (name, colour) => {
  console.log(arguments); // No object
};
vegetables('carrot', 'orange');

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

const sum = (x, y) => x + y;
console.log(sum(4, 5)); // 9

Кроме того, если нам нужно передать только один параметр, мы также можем опустить круглые скобки:

const multiplyByTwo = num => num * 2;
console.log(multiplyByTwo(2)); // 4

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

// won't work
const getObj = obj => {prop1: obj.prop1, prop2: obj.prop2}

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

// will work
const getObj = obj => ({prop1: obj.prop1, prop2: obj.prop2})

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

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

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

function doSomethingWithObject(object) { // nothing passed
    if (object && typeof object === 'object') {
// will not fire as we check if object is truthy and is an object
      console.log(object.property) 
    }
console.log(object.property) // error!
}
doSomethingWithObject()

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

function doSomethingWithObject(object = {}) {};```

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

function doSomethingWithObject(object = {property: 'hello'}, text = 'world') {
    console.log(object.property) // 'hello'
    console.log(text) // 'world'
};
doSomethingWithObject();

Сокращения собственности

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

let dinner = 'soup'
mealPlan = {
    dinner: dinner
}

Вы можете сделать его короче, написав «ужин» только один раз.

mealPlan = {
    dinner
}

Сокращения свойств очень полезны при деструктуризации. Деструктуризация - это извлечение свойств массива или объекта. Например, в приведенном ниже примере мы деструктурируем свойство данных директивно на основе результатов, возвращаемых axios.

axios.get('something').then(({data}) => {
 console.log(data); //data property from response object
}

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

let hugeObject = {'many properties here'}
const prepareData = ({prop1, prop2, prop3, prop4}) => ({
    prop1,
    prop2,
    prop3: prop3 ? 1 : 0,
    prop4
})
const payload = prepareData(hugeObject);

Вы также можете переименовать деструктурированные свойства:

const prepareData = ({prop1: name, prop2: surname}) => {};

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