Шпаргалка по современному JavaScript

Объявление переменных: var, const, let

В JavaScript переменные объявляют при помощи трёх операторов. При этом заданные через 

const

переменные изменить нельзя, а через

var

и

let

— можно. Поэтому если в коде предстоит изменить значение переменной, задавайте её с помощью

let

, если нет — через

const

.

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

  • Оператор
    var

    . Объявленные с его помощью переменные работают в пределах функции и не доступны вне её.

    Другой пример, демонстрирующий рамки области переменных:

    Переменные при выполнении оператора присваивания перемещаются в начало, что называется «поднятие переменных». Часть кода:

    при выполнении понимается как:

  • Оператор
    let

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

    Вот как это работает для не доступных до присвоения переменных, объявленных операторами 

    let

    и

    const

    :

    Переменные, объявленные с помощью

    var

    , доступны до присвоения. При использовании

    let

    и

    const

    — только после него. Этот феномен получил название «Временные мёртвые зоны». Кроме того, с помощью оператора

    let

    нельзя объявить другую переменную:

  • Оператор
    const

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

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

    const

    переменной для объектов:

    и массивов:

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

Стрелочные функции ввели в обновлении ES6 как альтернативный способ объявления и использования функций.

  • Краткость. Стрелочные функции короче традиционных, и каждый случай требует отдельного рассмотрения.
    • Явная/неявная функция
      return

      . Явная функция предполагает использование return в коде:

      Традиционный код отличается наличием ключевого слова:

      Поскольку перед

      return

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

      Мы убрали скобки и ключевое слово, но вывод всё равно

      x * 2

      . Если функция не возвращает значение (имеет побочные эффекты), это происходит ни явно, ни неявно. При необходимости возврата объекта, его заключают в скобки:

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

    • Отсутствие аргументов. В случае если аргументы не заданы, необходимо поставить скобки, иначе синтаксис будет неверным:

  • Привязка ключевого слова
    this

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

    this

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

    that = this

     или 

    self = this

    . А в стрелочных функциях значение

    this

    заимствуется из окружения, а не присваивается при создании нового ключевого слова. Например, используем

    setTimeout

    в функции 

    myFunc

    :

    Теперь в том же коде используем стрелочные функции:

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

С выходом версии ES2015 значение по умолчанию для параметра функции задаётся при помощи следующего синтаксиса:

Параметр по умолчанию применяется в двух случаях: когда он не задан или задан параметр

undefined

. При введении

null

параметр по умолчанию не применится.

Деструктурирование объектов и массивов

Деструктурирование — создание новых переменных путём извлечения данных из объектов и массивов. Например, извлечение параметров 

this.props

из React-проектов.

  • Объект. Рассмотрим для всех примеров объект:

    Без деструктурирования:

    Применяя деструктурирование:

  • Параметры функции. Деструктурирование применяется для извлечения параметров объектов в функции.
    Без деструктурирования:

    Извлекая параметр

    person

    , получим компактную функцию:

    Со стрелочными функциями код становится существенно меньше:

  • Массив. Рассмотрим массив:

    Без деструктурирования он выглядит так:

    С деструктурированием:

Методы массивов map/filter/reduce

Методы массивов пришли в JavaScript из функционального программирования. Используя три этих метода, вы избегаете циклов 

for

и

forEach

в большинстве ситуаций. Попробуйте вместо

for

использовать совокупность

map

,

filter

и

reduce

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

Для более детального наглядного объяснения возьмём массив:

  • Array.prototype.map().

    Что мы тут сделали?

    .map

    выполняет итерацию каждого элемента массива

    numbers

    и перемещает их в функцию. Цель функции — обработать и вернуть новую переменную, чтобы

    map

    мог заменить её.

    Теперь посмотрим на функцию отдельно, чтобы было понятнее:

    Метод часто используется со стрелочными функциями:

    Используем

    numbers.map(doubleN)

    и получаем

    , что равно

    [0, 2, 4, 6, 8, 10, 12]

    .

  • В случае если возвращать массив нет необходимости и нужен цикл с побочными эффектами, используйте

    for

    /

    forEach

    .

  • Array.prototype.filter().

    Метод также часто используется со стрелочными функциями:

    .filter

    осуществляет итерацию каждого элемента массива

    numbers

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

  • Array.prototype.reduce(). Цель метода — сократить переменные до одной после итерации.

    Метод также часто используется со стрелочными функциями:

    .reduce

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

    • функция 
      .reduce

       учитывает 2 параметра: вызываемую на каждом шаге итерации функцию и значение накопительной переменной (acc) на первом шаге итерации.

    • параметры функции: функция, принятая за значение
      .reduce

      , имеет 2 других — накопительную переменную (acc) и текущий элемент (n). Накопительная переменная равна возвращаемому на предыдущем шаге итерации значению функции. На первой ступени acc равна значению, принятому за второй параметр .reduce.

    Ступени итерации:

    1. acc = 0

      , поскольку мы ввели «0» вторым значением для reduce;

      n = 0

      , первый элемент массива

      number

      .
      Функция возвращает acc + n –> 0 + 0 –> 0

    2. acc = 0

      , значение, возвращённое функцией на предыдущей ступени итерации;

      n = 1

      , второй элемент массива

      number

      .
      Функция возвращает acc + n –> 0 + 1 –> 1

    3. acc = 1

      , значение, возвращённое функцией на предыдущей ступени итерации;

      n = 2

      , третий элемент массива

      number

      .
      Функция возвращает acc + n –> 1 + 2 –> 3

    4. acc = 3

      , значение, возвращённое функцией на предыдущей ступени итерации;

      n = 3

      , четвёртый элемент массива

      number

      .
      Функция возвращает acc + n –> 3 + 3 –> 6

    5. (…действия повторяются до последнего шага)
      acc = 15

      , поскольку это значение функция вернула на предыдущей ступени

      n = 6

      , последний элемент массива

      number

      .
      На последнем шаге функция возвращает acc + n –> 15 + 6 –> 21

Оператор spread(…)

Его добавили в обновлении ES2015, чтобы элементы итерации (например массива) можно было использовать в качестве нескольких элементов в коде.

  • Объектные литералы.

Возьмём два массива:

В

arr2

первый аргумент — массив, поскольку читает содержимое

arr1

. Но нам нужно сделать

arr2

массивом, состоящим из последовательности букв. Для этого используем spread и получим необходимый результат:

  • Оставшиеся параметры функции. С их помощью мы можем создать массив с неучтёнными параметрами функции. Объект
    arguments

     относится к функциям, равным массиву переданных функции аргументов.

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

  • Расширение свойств объекта.

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

Зададим переменную для свойств объекта. Если её имя совпадёт с названием свойства, можно сделать следующее:

Если вы объявляли объектный литерал в версиях до ES2015 или хотели использовать переменную в качестве значения свойств объекта, то пришлось бы писать:

Слишком много повторений, не так ли? Поэтому с выходом ES2015 при совпадении переменной с названием свойства, достаточно такого кода:

Объекты «промисы»

Промис — это объект, который используется для упорядочивания синхронных и асинхронных операций. При использовании промисов код становится чище, поэтому они всё чаще встречаются в проектах.

AJAX-запрос при выполнении не является синхронным, поскольку ответ от ресурса идёт какое-то время. Он может вообще не прийти, если ресурс не доступен (404). Для решения этой проблемы в ES2015 добавили промисы, которые принимают 3 состояния:

  • ожидание;
  • выполнен;
  • отклонён.

Представим, что нам нужно создать Ajax-запрос до ресурса X. Используем для этого метод

jQuery.get()

:

Объект Promise выполняет функцию

executor

 с аргументами

resolve

и

reject

. Эти аргументы выполняются по завершении операции как и функции, которые переводят промис из состояния ожидания в состояние выполнения или отклонения. Функция

executor

выполняется сразу после создания промиса в статусе ожидания. Как только аргументами функции становятся

resolve

или

reject

, промис использует необходимые методы.

Используем методы промиса, чтобы получить его выполнение или ошибку:

В случае сдержанного промиса выполняется resolve и функция с методом 

.then

. Иначе выполняется reject и функция с методом 

.catch

. Также обработчик будет выполнен при сдержанном или нарушенном промисе, что приведёт к отсутствию «состояния гонки» между завершением асинхронной операции и применением обработчика.

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

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

Теговые шаблоны

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

...

). Библиотека styled-components написана с применением теговых шаблонов.

Ниже приведён небольшой пример их работы:

Другой интересный пример:

Инструкции импорта и экспорта

Экспорт функций/объектов из модулей ES6 и импорт значений из них.

  • Именованные импорт/экспорт используют для нескольких величин (ими могут быть лишь объекты первого класса):

Несмотря на внешнюю схожесть именных импортов с деструктурированием, синтаксис отличается. Они не поддерживают значения по умолчанию или вложенное деструктурирование. Кроме того, можно использовать дополнительное имя, но синтаксис отличается от используемого при деструктурировании:

  • Импорт/экспорт по умолчанию.

Для одного модуля доступен один экспорт по умолчанию. Экспорт может быть функцией, классом, объектом и т.д. Значение рассматривается как «основное», поскольку так его проще импортировать:

Экспорт функции:

Ключевое слово this

Поведение этого ключевого слова в JavaScript отличается от других языков и зависит от вызова функции.

Классы

JavaScript — прототип-ориентированный язык программирования. Классы ввели как синтаксический сахар для прототип-ориентированного наследования в ES6. Слово «класс» смутит вас, если вы знакомы с классами в других языках программирования. Попробуйте посмотреть иначе: прочитайте о прототипах и их поведении в JavaScript. До ES6 синтаксис прототипов выглядел следующим образом:

С синтаксисом классов в ES6: