12 концепций JavaScript, о которых нужно знать
JavaScript — это сложный язык. Если вы, на любом уровне, занимаетесь JavaScript-разработкой, это значит, что вам жизненно необходимо понимать базовые концепции этого языка. В материале, перевод которого мы сегодня публикуем, рассмотрены 12 важнейших концепций JavaScript. Конечно, JavaScript-разработчику нужно знать гораздо больше, но без того, о чём мы будем сегодня говорить, ему точно не обойтись.
1. Переменные, хранящие значения и ссылки
Понимание того, как именно в JavaScript назначаются значения переменных крайне важно для тех, кто хочет писать правильно работающий код. Непонимание этого механизма ведёт к написанию программ, в которых значения переменных могут непреднамеренно меняться.
JavaScript, если некая сущность имеет один из примитивных типов (в частности — это типы Boolean , null , undefined , String и Number ), всегда работает со значением этой сущности. То есть, в соответствующую переменную записывается именно значение. Если же речь идёт об объекте (это, например, типы Object , Array , Function ), то, при назначении его переменной, в неё записывается ссылка на него, адрес, по которому он расположен в памяти.
Рассмотрим пример. В следующем фрагменте кода в переменную var1 записана строка. После этого в переменную var2 записано значение переменной var1 . Так как переменная var1 имеет примитивный тип ( String ), то в var2 будет записана копия строки, имеющейся в var1 . Это позволяет рассматривать var2 как переменную, полностью независимую от var1 , хотя и хранящую то же значение, что и var1 . Запись в var2 нового значения на var1 не влияет.
Теперь рассмотрим пример работы с объектами.
Как видите, здесь мы работаем с переменной var2 , а то, что с ней происходит, отражается и на переменной var1 так как они хранят ссылку на один и тот же объект. Несложно представить себе к чему подобное может привести в реальном коде в том случае, если некто решит, что переменные, хранящие объекты, ведут себя так же, как переменные, хранящие значения примитивных типов. Особенно это неприятно, например, в случаях, когда создают функцию, которая рассчитана на работу с переданным ей объектным значением, и эта функция данное значение непреднамеренно изменяет.
2. Замыкания
Замыкание — это важный паттерн проектирования в JavaScript, который позволяет организовать защищённую работу с переменными. В следующем примере функция createGreeter() возвращает анонимную функцию, у которой есть доступ к предоставленному исходной функции аргументу greeting , содержащему строку Hello . Ссылка на эту анонимную функцию записывается в переменную sayHello . После этого, сколько раз бы мы ни вызывали функцию sayHello() , у неё всегда будет доступ к значению greeting . При этом доступ к greeting будет только у анонимной функции, ссылка на которую записана в sayHello .
Это был очень простой пример. Если же рассмотреть нечто, более близкое к реальному миру, то можно представить себе, например, функцию для подключения к некоему API (назовём её apiConnect() ), которой, при первом её вызове, передаётся ключ доступа к API. Эта функция, в свою очередь, возвращает объект, содержащий несколько методов, которые пользуются переданным apiConnect() ключом доступа к API. При этом ключ хранится в замыкании и при вызове этих методов упоминать его больше не требуется.
3. Деструктурирующее присваивание
Если вы до сих пор не пользовались деструктурирующим присваиванием в JavaScript, то это пора исправить. Деструктурирующее присваивание представляет собой распространённый способ извлечения свойств объектов с использованием аккуратной синтаксической конструкции языка.
Если извлечённым свойствам нужно присвоить имена, отличающиеся от тех, которые они имеют в объекте, можно поступить так:
В следующем примере деструктурирование используется для аккуратной передачи значений, хранящихся в свойствах объекта person , функции introduce() . Это — пример того, как данная конструкция используется при объявлении функции для извлечения данных из переданного ей объекта с параметрами. Кстати, если вы знакомы с React, то вы, вероятно, уже такое видели.
4. Оператор spread
Оператор spread — это довольно простая конструкция, которая может показаться неподготовленному человеку непонятной. В следующем примере есть числовой массив, максимальное значение, хранящееся в котором, нам нужно найти. Мы хотим использовать для этого метод Math.max() , но он с массивами работать не умеет. Он, в качестве аргументов, принимает самостоятельные числовые значения. Для того чтобы извлечь из массива его элементы мы используем оператор spread, который выглядит как три точки.
5. Оператор rest
Оператор rest позволяет преобразовывать любое количество аргументов, переданных функции, в массив.
6. Методы массивов
Методы массивов часто дают разработчику удобные инструменты, позволяющие красиво решать самые разные задачи по преобразованию данных. Я иногда отвечаю на вопросы на StackOverflow. Среди них часто попадаются такие, которые посвящены чему-то вроде тех или иным способов работы с массивами объектов. Именно в таких ситуациях методы массивов особенно полезны.
Здесь мы рассмотрим несколько таких методов, объединённых по принципу их схожести друг с другом. Надо отметить, что тут я расскажу далеко не обо всех методах массивов. Найти их полный список можно на MDN (кстати, это — мой любимый справочник по JavaScript).
▍Методы map(), filter() и reduce()
Методы массивов map() , filter() и reduce() позволяют трансформировать массивы или сводить массивы к одному значению (которое может быть объектом).
Метод map() возвращает новый массив, содержащий трансформированные значения обрабатываемого массива. То, как именно они будут трансформированы, задаётся в передаваемой этому методу функции.
Метод filter() возвращает массив элементов, проверяя значения которых функция, переданная этому методу, возвратила true .
Метод reduce() возвращает некое значение, представляющее собой результат обработки всех элементов массива.
▍Методы find(), findIndex() и indexOf()
Методы массивов find() , findIndex() и indexOf() легко перепутать друг с другом. Ниже даны пояснения, помогающие понять их особенности.
Метод find() возвращает первый элемент массива, соответствующий заданному критерию. Этот метод, найдя первый подходящий элемент, не продолжает поиск по массиву.
Обратите внимание на то, что в нашем примере заданному критерию соответствуют все элементы массива, следующие за тем, который содержит число 5, но возвращается лишь первый подходящий элемент. Этот метод весьма полезен в ситуациях, в которых, пользуясь для перебора и анализа массивов циклами for , такие циклы, при обнаружении в массиве нужного элемента, прерывают, используя инструкцию break .
Метод findIndex() очень похож на find() , но он, вместо того, чтобы возвращать первый подходящий элемент массива, возвращает индекс такого элемента. Для того чтобы лучше понять этот метод — взгляните на следующий пример, в котором используется массив строковых значений.
Метод indexOf() очень похож на метод findIndex() , но он принимает в качестве аргумента не функцию, а обычное значение. Использовать его можно в том случае, если при поиске нужного элемента массива не нужна сложная логика.
▍Методы push(), pop(), shift() и unshift()
Методы push() , pop() , shift() и unshift() применяются для добавления в массивы новых элементов и для извлечения из массивов уже имеющихся в них элементов. При этом работа производится с элементами, находящимися в начале или в конце массива.
Метод push() позволяет добавлять элементы в конец массива. Он модифицирует массив, и, после завершения работы, возвращает элемент, добавленный в массив.
Метод pop() удаляет из массива последний элемент. Он модифицирует массив и возвращает удалённый из него элемент.
Метод shift() удаляет из массива первый элемент и возвращает его. Он тоже модифицирует массив, для которого его вызывают.
Метод unshift() добавляет один или большее количество элементов в начало массива. Он, опять же, модифицирует массив. При этом, в отличие от трёх других рассмотренных здесь методов, он возвращает новую длину массива.
▍Методы slice() и splice()
Эти методы используются для модификации массива или для возврата некоей части массива.
Метод splice() меняет содержимое массива, удаляя существующие элементы или заменяя их на другие элементы. Он умеет и добавлять в массив новые элементы. Этот метод модифицирует массив.
Следующий пример, если описать его обычным языком, выглядит так: нужно, в позиции массива 1 , удалить 0 элементов и добавить элемент, содержащий b .
Метод slice() возвращает неглубокую копию массива, содержащую его элементы, начиная с заданной начальной позиции и заканчивая позицией, предшествующей заданной конечной позиции. Если при его вызове задана только начальная позиция, то он вернёт весь массив, начиная с этой позиции. Этот метод не модифицирует массив. Он лишь возвращает описанную при его вызове часть этого массива.
▍Метод sort()
Метод sort() выполняет сортировку массива в соответствии с условием, заданным переданной ему функцией. Эта функция принимает два элемента массива (например, они могут быть представлены в виде параметров a и b ), и, сравнивая их, возвращает, в том случае, если элементы менять местами не надо, 0, если a нужно поставить по меньшему индексу, чем b — отрицательное число, а если b нужно поставить по меньшему индексу, чем a — положительное число.
Если вы не можете, впервые ознакомившись с этими методами, их запомнить — ничего страшного. Самое главное это то, что вы теперь знаете о том, что умеют стандартные методы массивов. Поэтому, если вы и не можете сходу вспомнить особенности того или иного метода, то, что вы о нём знаете, позволит вам быстро найти то, что нужно, в документации.
7. Генераторы
Генераторы в JavaScript объявляют, используя символ звёздочки. Они позволяют задавать то, какое значение будет возвращено при очередном вызове метода next() . Генераторы могут быть рассчитаны на возврат ограниченного количества значений. Если подобный генератор возвратил все такие значения, то очередной вызов next() вернёт undefined . Можно создавать и генераторы, рассчитанные на возврат неограниченного количества значений с использованием циклов.
Вот генератор, рассчитанный на возврат ограниченного числа значений:
А вот генератор, рассчитанный на возврат бесконечного количества значений посредством цикла.
8. Операторы проверки равенства (==) и строгого равенства (===) значений
Любому JS-разработчику чрезвычайно важно понимать разницу между операторами равенства ( == ) и строгого равенства ( === ). Дело в том, что оператор == , перед сравнением значений, выполняет преобразование их типов (что может приводить к странным, на первый взгляд, последствиям), а оператор === преобразование типов не производит.
9. Сравнение объектов
Мне периодически приходится видеть, как новички в JS-программировании совершают одну и ту же ошибку. Они пытаются напрямую сравнивать объекты. Переменные, в которых «хранятся» объекты, содержат в себе ссылки на них, а не сами эти объекты.
Так, например, в следующем примере объекты выглядят одинаково, но при их прямом сравнении нам сообщают о том, что объекты это разные, так как каждая из переменных содержит ссылку на собственный объект и эти ссылки друг другу не равны.
При этом в следующем примере оказывается, что joe1 равно joe2 так как обе переменные хранят ссылку на один и тот же объект.
Один из методов настоящего сравнения объектов заключается в их предварительном преобразовании в формат JSON-строк. Правда, у такого подхода есть одна проблема, которая заключается в том, что в полученном строковом представлении объекта не гарантируется определённый порядок следования его свойств. Более надёжный способ сравнения объектов заключается в использовании специальной библиотеки, содержащей средства для глубокого сравнения объектов (например — это метод isEqual() библиотеки lodash).
Для того чтобы лучше разобраться с тонкостями сравнения объектов и осознать возможные последствия записи в разные переменные ссылок на одни и те же объекты, взгляните на первую концепцию JS, рассмотренную в этом материале.
10. Функции обратного вызова
Функции обратного вызова — это довольно простая концепция JavaScript, с которой у новичков иногда возникают сложности. Рассмотрим следующий пример. Здесь функция console.log (именно так — без скобок) передаётся функции myFunc() в качестве функции обратного вызова. Эта функция устанавливает таймер, по срабатыванию которого вызывается console.log() и переданная функции myFunc() строка выводится в консоль.
11. Промисы
После того, как вы освоите функции обратного вызова и начнёте всюду их использовать, вы очень скоро можете обнаружить себя в так называемом «аду коллбэков». Если вы и правда там оказались — взгляните на промисы. Асинхронный код можно обернуть в промис, и, после его успешного выполнения, сообщить системе об успешном разрешении промиса, вызвав соответствующий метод, а если что-то пойдёт не так — вызвать метод, указывающий на это и отклонить промис. Для того чтобы обработать результаты, возвращаемые промисом, воспользуйтесь методом then() , а для обработки ошибок — методом catch() .
12. Конструкция async/await
После того, как вы поработаете с промисами, то вам, вполне возможно, захочется чего-то большего. Например — освоить конструкцию async/await. Она представляет собой «синтаксический сахар» для промисов. В следующем примере мы создаём, с помощью ключевого слова async , асинхронную функцию, и в ней, пользуясь ключевым словом await , организуем ожидание выполнения промиса greeter .
Итоги
Если то, о чём мы здесь говорили, было вам до этого незнакомо, то вы, скорее всего, хотя бы немного, но выросли над собой, прочитав эту статью. Если же вы не нашли тут ничего нового, тогда хочется надеяться, что этот материал дал вам возможность попрактиковаться и укрепить ваши знания JavaScript.
Уважаемые читатели! Какие ещё концепции JavaScript вы добавили бы в эту статью?
7 советов начинающему Javascript-разработчику

Привет! Это продолжение моей статьи про JavaScript и то, как стать разработчиком. Эта статья предназначена для того, чтобы показать вам, за что держаться во время учебы. На мой взгляд, следующие семь советов помогут вам на пути к тому, чтобы стать компетентным разработчиком JavaScript. Они записаны в произвольном порядке. Давайте посмотрим!
1. Понять простой JavaScript
Как бы просто это ни звучало, на это часто не обращают внимания. Существует огромный контраст между разработчиками, которые могут использовать популярные инструменты и фреймворки, такие как React, Vue и Angular с одной стороны, и разработчиками, которые знают JavaScript наизусть, с другой.
Очевидно, они не исключают друг друга. Хороший разработчик на JavaScript сравнительно легко освоит новые фреймворки. Но наоборот, это может быть неправдой: если вам нравится фреймворк вроде React, вы не обязательно являетесь экспертом по JavaScript.
Я не могу переоценить, какую ценность это принесет вам, если вы знаете основы реального языка. Всякий раз, когда вы видите фрагмент кода JavaScript, написанный ли вашим коллегой или участником одной из упомянутых выше библиотек, вы должны хотя бы иметь общее представление о том, что происходит.
Основные принципы, такие как области действия и замыкание, не должны быть для вас загадкой. То же самое касается сборки мусора, прототипирования и синтаксиса.
Взгляните на следующий код:
Что здесь происходит? Вы знаете? И вы можете объяснить почему? Вы должны, и должны знать JavaScript, и его синтаксис, наизусть. Не потому, что вам так сказал какой-то случайный автор, а потому, что рано или поздно вы наткнетесь на стену, если вы этого не сделаете. Подобные вопросы будут задаваться во время собеседований по кодированию. Они попросят вас подробно объяснить, что происходит. Не хочу не слишком напугать некоторых из вас, но вопросы будут намного сложнее, чем этот.
Не учитесь только угождать другим людям, например рекрутерам, интервьюерам или потенциальным работодателям. Научитесь добавлять ценность. Цените себя как компетентного разработчика JavaScript. Вы принесете эту ценность с собой, куда бы вас ни привела жизнь.
2. Прочтите качественный контент
Читаю — не смотрю. Есть причина, по которой ученых и интеллектуалов часто называют книжными червями, а не экранными червями. Беглый просмотр бесчисленных некачественных руководств и видео далеко не уведет. Чаще всего вы даже не сосредотачиваетесь, когда читаете или смотрите их.
«Ад на обучающих курсах — это когда мы заканчиваем обучение с чувством небольшого количества знаний. И если вы осмеливаетесь написать код для себя, вы чувствуете себя подавленным. Вы не знаете, с чего начать или даже что делать».
Назовите меня старомодным, но я твердо верю в традиционный носитель, называемый книгами. Они используются на протяжении тысячелетий, и этому есть причина. Я достаточно современен, чтобы признать, что вам физически не обязательно владеть книгой, и существует множество (цифровых) альтернатив для чтения их содержания, но это выходит за рамки моей точки зрения. (Хекслет — хороший пример).
Книги — действительно ценный источник информации, независимо от того, как вы их употребляете. Вы не можете написать книгу за одну ночь (поверьте мне на слово). Это означает, что автор приложил много усилий для сбора и записи этой информации. То же самое не всегда можно сказать о контенте, который вы бесплатно найдете в Интернете.
Еще одно важное преимущество чтения книги состоит в том, что она требует полного сосредоточения. Когда вы садитесь, открываете (физическую) книгу и начинаете ее читать, это все, что вы делаете. Вы не можете читать книгу и разговаривать с другом, или играть с одним из ваших детей одновременно.
Возьмите хорошую книгу. Выключите телефон, изолируйте себя на несколько часов и прочтите ее. И да, они стоят денег. Но это вложение. Инвестиция в вас, как в девелопера.
«Секреты JavaScript-ниндзя» Джона Ресига (создателя jQuery и бывшего сотрудника Mozilla) и др. — одна из лучших книг о JavaScript, которые я когда-либо читал. Я действительно считаю, что это золотая жила. Он лежит на моей книжной полке. И порой, спустя столько лет, я считаю себя ниндзя.
3. Ознакомьтесь с различными концепциями
С учетом сказанного, пожалуйста, поиграйте со всеми популярными фреймворками. Список, кажется, меняется день ото дня, но вы не ошибетесь, взглянув на React, Vue, Angular, Gatsby и Next.js, и это лишь некоторые из них.
В день или вечер, когда ничего не происходит, включите свой ноутбук и создайте новый проект с одним из них. Все они хорошо задокументированы, и начало работы часто занимает считанные минуты. Поиграйте, напишите код. Почувствуйте каждый из них и составьте о них мнение, пусть даже поверхностное.
Я не могу сосчитать, сколько раз я брал интервью у потенциальных новых коллег, и, спросив, например, почему они предпочитают работать с React, они, например, ответили: «Потому что я читал, что это самый популярный фреймворк на сегодняшний день».
Справедливо. Это могло быть правдой. Или нет. Кто знает? Но почему вы думаете, что это популярно и круто? Какие функции вам больше всего нравятся по сравнению с функциями Vue или Angular? Что в Next.js лучше React и наоборот?
В девяти случаях из десяти меня встречает тишина. Они даже не пробовали. Сформируйте образованное мнение. Ваше мнение. И возьмите их с собой на пути к тому, чтобы стать компетентным разработчиком JavaScript.
4. Понять HTML и CSS
Не забывайте, что HTML и CSS являются основой Интернета. Строительные блоки. Все, на что вы смотрите, — это элементы HTML с некоторым стилем.
React, Vue, Angular? Какими бы классными они ни были, все они в конце концов «выплевывают» HTML. Вы не можете игнорировать HTML и CSS, или относиться к ним легкомысленно. Я встречал множество программистов, которые были очень хорошими разработчиками JavaScript, но мало знали о HTML и CSS. Это проблематично.
Конечно, если вы хотите стать внутренним разработчиком JavaScript, это не будет критично. Но есть вероятность, что вы в конечном итоге создадите веб-сайты и веб-приложения, и тогда потребуется твердое понимание HTML, CSS и JavaScript как трио. Не стоит недооценивать это. Изучение JavaScript может быть трудным. То же можно сказать и о HTML и CSS.
5. Уважайте старших разработчиков
Я всегда удивляюсь, когда вижу молодых разработчиков, которые не уважают своих коллег, и не стараются их внимательно выслушать. Когда вы, будучи младшим, разговариваете со старшим разработчиком, вам не следует делать ничего, кроме как усваивать их мнение. Слушать и учиться. В конце концов, вы разговариваете с человеком, который уже много лет выполняет вашу работу. Они были там и все это видели. И хотя это может повредить вашему эго, у них гораздо больше знаний и навыков, чем у вас.
Не поймите меня неправильно: хороший Senior-разработчик также будет слушать людей, которые только что вышли на сцену. Каждый может добавить ценность — независимо от его возраста или уровня опыта. Наставники и коллеги — прекрасный источник информации для начинающих разработчиков. Относитесь к ним именно так.
6. Будьте любопытными, исследуйте и приобретайте знания
Это должно быть чертой личности №1 каждого серьезного разработчика JavaScript.
Мир JavaScript, Интернета и технологий в целом быстро меняется. Это означает, что вы должны постоянно держать глаза и уши открытыми. Следить за последними и лучшими — это одно, но не забывайте также стремиться к твердому пониманию сегодняшних решений, инструментов и фреймворков.
Полюбопытствовать. Если вы чего-то не понимаете, не копируйте это вслепую в свой проект. Конечно, это сработает и решит конкретную проблему. Но вы не сможете назвать это решение частью своего репертуара. Копировать чужие решения слишком просто и далеко не уедешь.
Загляните за шторы. Почему это решение работает? Как это работает? Могу ли я воспроизвести это сам в следующий раз? Имею ли я сейчас четкое представление об этом? Если нет, то пора прочитать эту книгу, поговорить со старшим разработчиком или поискать в Интернете, пока вы не поймете все до единого.
Ваша цель не должна заключаться в исправлении ошибок или выполнении задач. Ваша главная цель должна заключаться в том, чтобы стать компетентным разработчиком JavaScript. А это значит, что вам нужно учиться. Будьте любопытными, исследуйте и получайте новые знания с каждым днем.
7. Напишите код. А потом напишите еще
Мы можем говорить, читать или писать столько сообщений в блогах, сколько захотим. В конце концов, вы должны убедиться, что вы пишете код, пишете код и пишете еще код.
Автомеханики не становятся автомеханиками, слушая своего учителя. Они становятся экспертами и хорошими автомеханиками, когда их руки грязные, а лицо покрыто маслом и жиром, когда они пытаются ослабить труднодоступный болт. Или что-то в этом роде — вы меня поняли.
Я сам читал и следил за многими, многими учебниками. Но я всегда следил за тем, чтобы писать код, пока я это делал. Даже если бы я мог скопировать и вставить предоставленный код, я этого не сделал. Я всегда сам писал (точно такой же) код. Видеть код — это одно. Дословно написать самому — совсем другое дело. Вот тогда он становится частью вас и вашего репертуара. Заключение
Вопреки тому, что иногда говорят в Интернете, стать компетентным разработчиком JavaScript непросто. Это требует упорного труда, самоотверженности, усилий и времени. Удачи вам.
Никогда не останавливайтесь: В программировании говорят, что нужно постоянно учиться даже для того, чтобы просто находиться на месте. Развивайтесь с нами — на Хекслете есть сотни курсов по разработке на разных языках и технологиях
10 вещей, которые надо знать, чтобы стать мастером JavaScript
![]()
Полагаю, вы веб-разработчик. Надеюсь, ваши дела идут хорошо, у вас отличная работа, возможно вы работаете на себя или в качестве фрилансера. Будущее этой сферы выглядит многообещающе. Может быть, вы только начинаете свою карьеру разработчика, а может быть, вы работаете уже многие годы. Какими бы навыками JavaScript вы ни обладали, всегда полезно освежить некоторые знания или изучить что-то новое. Ниже представлены 10 вещей, которые вы обязательно должны знать, чтобы считаться мастером JavaScript.
1. Поток команд
Пожалуй, это базовый пункт в этом списке. И один из важнейших, может быть, даже и самый важный. Если вы не знаете, как работает код, вам придется очень тяжело.Поэтому знание базового потока команд просто необходимо.
- if else — если вы этого не знаете, как вообще раньше писали код?
- switch —то же, что и if else, только в чуть усложненном виде. Применяйте его, когда у вас несколько различных вариантов.
- for — циклы созданы, чтобы вам не приходилось повторяться. Полезен будет не только простой for , `for of`и for in тоже весьма пригодятся. Большим достоинством циклов for является блокировка, поэтому в них можно использовать async await.
- Предварительные условия — Применение ternary и логических операторов значительно облегчит вашу жизнь. Особенно если вы производите промежуточные действия и не хотите сохранять значения, чтобы использовать их дальше.
2. Устранение ошибок
Это заняло у меня немало времени. Не важно, работаете вы с front-end или back-end, первый год работы вы всегда будете пользоваться console.log или console.error для “устранения” ошибок. Для того, чтобы писать качественные приложения, вам нужно избавиться от этой привычки, и вместо использования ленивых логов устранять ошибки правильно. Разберитесь, как написать свой собственный конструктор Error, как правильно находить ошибки, а также как показывать пользователю, в чем проблема.
3. Модели данных
Постоянно просматривая ваш код, вы должны решать, когда стоит объединить определённые блоки информации, а когда этого делать не нужно. Это применимо не только к созданию моделей данных, но также функций, параметров, объектов или переменных. Например:
4. Асинхронность
Это очень важный аспект JavaScript. Вызываете ли вы данные из back-end или асинхронно выполняете запросы в сам back-end, в любом случае вы столкнетесь с асинхронностью и связанными с ней проблемами. Если вы не знаете, что такое асинхронность, вы столкнетесь со странной ошибкой, которую будете пытаться решить пару часов. Если вы знаете, что это, но не знаете, что с этим делать, вы попадете в ад обратных вызовов. Лучше в ваших приложениях использовать промисы и/или async await.
5. Управление DOM
Это интересная тема. Чаще всего, описывая обычную работу программиста, про это забывают. Может быть, вы изучили jQuery, и вам и не нужно было учиться навыкам управления DOM. Может, вы просто работаете с front-end фреймворком, где управление DOM используется редко. Однако я считаю, что это очень важный аспект для понимания JavaScript, как минимум во front-end. Понимание того, как работает DOM и как получать доступ к элементам, поможет вам лучше понять, как работают сайты. К тому же, обязательно наступит момент, когда вам придется работать с DOM, даже если вы используете современные front-end фреймворки, и вы точно не хотите вводить jQuery в ваш package.json , чтобы просто получить доступ к элементу.
6. Node.js / Express
Даже front-end разработчики должны знать азы node.js. Хорошо, если вы также будете знать, как запустить простой сервер Express, добавить новые маршруты или изменить существующие. JavaScript хорошо подходит для написания скриптов, которые помогут в автоматизации выполнения задач. Таким образом, зная, как читать файлы и работать с путями к файлу и буферами, вы получите набор инструментов для создания чего угодно.
7. Функциональный подход
Спорам между любителями функционального и объектно-ориентированного программирования нет конца. С помощью обоих подходов вы можете достичь одних и тех же целей. А JavaScript всё упрощает, так как объединяет оба этих подхода. Библиотеки вроде lodash предоставляют вам отличный набор средств для создания приложений при помощи функционального подхода. Сейчас вам даже не придется использовать какие-то внешние библиотеки. Многие наиболее важные функции были внедрены в официальных версиях JavaScript. Вам обязательно нужно научиться использовать map `reduce` filter `forEach` и `find`.
8. Объектно-ориентированный подход
Вам также стоит познакомиться и с объектно-ориентированным JavaScript, если вы хотите полностью освоить его. Долгое время в работе я пренебрегал этой частью, и всегда находил обходные пути. Но иногда действительно стоит применять объекты/классы и экземпляры, чтобы использовать определенные функции. Классы широко используются в React, MobX и пользовательских конструкторах.
9. Front-end фреймворк
React.js, Angular и Vue.js составляют “большое трио”. Если сейчас поискать вакансии, практически в каждой из них будет требоваться знания чего-то из этого. Несмотря на то, что они быстро изменяются, важно понимать основную суть этих библиотек и фреймворков, чтобы понимать, как работают приложения. К тому же, с их помощью легче писать приложения. Если вы ещё не выбрали, что изучать, я советую React.js. Последние пару лет я работаю с этой библиотекой, и ни разу не пожалел об этом.
10. Объединение / транспиляция
К сожалению, это большая часть разработки приложений. С одной стороны, мне не стоит говорить “к сожалению”, потому что здорово иметь возможность писать код, используя все новые функции. С другой стороны, я так говорю, потому что всегда нужно помнить о том, что существуют старые браузеры, которые эти функции не поддерживают. Поэтому нам приходится транспилировать наш код, чтобы он обрабатывался старыми браузерами. Если вы работает с node.js, то прибегаете к транспиляции реже. Для транспиляции обычно используют babel.js, изучите его. Для объединения кода и связи всех частей между собой существует пара способов. Раньше наиболее распространенным был Webpack. Но некоторое время назад откуда ни возьмись появился parcel, на данный момент мне он нравится больше. Пусть он и не идеален, но он эффективнее и проще в настройке, чем Webpack.
Бонус: Регулярные выражения
Это не относится конкретно к JavaScript, но всё же очень полезно, хоть и сложно. Изучение синтаксиса регулярных выражений, определённо, займет у вас некоторое время, а запомнить все варианты просто невозможно.
Тестирование
Тестирование — это действительно очень важная часть разработки приложений, в том числе и в JavaScript. При написание кода, прежде чем запустить функцию, вы (в идеале) должны провести тестирование, пусть даже и ручное. Лучше будет применять автоматическое тестирование. Существуют разные типы тестов: модульное, сквозное, нагрузочное тестирование, проверки безопасности и front-end (например, подключен компонент или нет). Также есть множество различных тестовых сред: enzyme, jasmine, mocha, chai, и т.д. Сейчас мне больше всего нравится ava.js, советую изучить её, если вы до этого не работали с автоматическим тестированием.
Надеюсь, вы итак уже знаете всё, о чем я написал. Если нет, поработайте над этим и постарайтесь стать мастером JavaScript! Это действительно стоит того. Помните, что в программировании самое главное — это практика. Поэтому если вы не знакомы с какими-то из описанных тем, или знакомы только в теории, восполните пробелы. Это пригодится вам в будущем.
Памятка по современному JavaScript
Cheatsheet for the JavaScript knowledge you will frequently encounter in modern projects.
Памятка по современному JavaScript
За картинку спасибо Ahmad Awais ⚡️
Введение
Мотивация
В этом документе собраны возможности языка JavaScript, с которыми вы наверняка столкнетесь в современных проектах и примерах кода.
Цель этого руководства — не обучить вас JavaScript с нуля, а помочь разработчикам с базовыми знаниями, которые при изучении современных кодовых баз (или, скажем, React) сталкиваются со сложностями из-за использованных в них концепций JavaScript.
Иногда я буду давать личные советы, которые могут быть спорными, но постараюсь упоминать, что это личное мнение.
Примечание: Большинство представленных здесь понятий взяты из обновления языка JavaScript (ES2015, которое часто называют ES6). Вы можете найти новые возможности из этого обновления здесь; они хорошо описаны.
Дополнительные ресурсы
Если вам сложно разобраться с каким-то понятием, рекомендую искать ответы на вопросы на следующих ресурсах:
-
. . . — бесплатный курс от Udacity. . для поиска специализированных блогов и ресурсов. .
Содержание
Понятия
Объявление переменных: var , const , let
В JavaScript есть три ключевых слова, отвечающих за объявление переменных, и у каждого из них свои особенности. Эти слова − var , let и const .
Краткое объяснение
Переменным, объявленным с помощью ключевого слова const , нельзя позже присвоить новое значение, в то время как переменным, объявленным с помощью let или var , можно.
Я рекомендую всегда объявлять переменные ключевым словом const , а let использовать только в том случае, если позже эту переменную понадобится изменить или переопределить.
| Область видимости | Можно переопределять | Можно изменять | Временная мертвая зона | |
|---|---|---|---|---|
| const | Блок | Нет | Да | Да |
| let | Блок | Да | Да | Да |
| var | Функция | Да | Да | Нет |
Пример кода
Подробное объяснение
Область видимости переменной определяет, где эта переменная доступна в коде.
Областью видимости переменных, объявленных с помощью var , является функция. Это означает, что если переменная была создана внутри функции, то у всего внутри этой функции есть доступ к данной переменной. Кроме того, переменная с областью видимости внутри функции недоступна за пределами этой функции.
Можно думать об этом вот так: если у переменной область видимости Х, то эта переменная — как бы свойство Х.
Вот менее очевидный пример области видимости переменных:
Кроме этого, переменные, объявленные с помощью ключевого слова var , при выполнении кода перемещаются в начало области видимости. Это называется поднятие переменных.
Этот фрагмент кода:
при выполнении понимается как:
var и let примерно одинаковы, в то время как переменные, объявленные словом let :
- имеют в качестве области видимости блок;
- недоступны до объявления;
- не могут быть повторно объявлены в той же области видимости.
Давайте разберемся, в чем особенности блочной области видимости, используя предыдущий пример:
Теперь разберемся, что значит «переменные, объявленные с помощью let и const , недоступны до их объявления»:
В отличие от переменных, объявленных через var , попытка обратиться к переменной let или const до её объявления вызовет ошибку. Этот феномен часто называют Временной мёртвой зоной.
Примечание: строго говоря, объявления переменных с использованием let и const тоже поднимаются, однако их инициализация — нет. Они сделаны так, что использовать их до инициализации нельзя. Поэтому интуитивно кажется, что такие переменные не поднимаются, но на самом деле это не так. Больше информации можно найти в этом очень подробном объяснении.
В дополнение к сказанному: нельзя повторно объявить переменную, объявленную с помощью let :
const
Переменные, объявленные через const , ведут себя так же, как переменные, объявленные через let , но к тому же их нельзя переопределять.
Итак, переменные, объявленные с помощью const :
- имеют в качестве области видимости блок;
- недоступны до объявления;
- не могут быть повторно объявлены в той же области видимости;
- не могут быть переопределены.
Но есть одна тонкость: переменные, объявленные с помощью const , не являются неизменными! А именно, это означает, что объекты и массивы, объявленные с помощью const , могут быть изменены.
В случае объектов:
В случае массивов:
Дополнительные материалы
Стрелочные функции
В обновлении JavaScript ES6 добавлены стрелочные функции — новый синтаксис записи функций. Вот некоторые их преимущества:
- краткость;
- this берется из окружающего контекста;
- неявный возврат.
Пример кода
- Краткость и неявный возврат.
Внутри стрелочной функции значение this такое же, как и во внешней области видимости. В принципе, со стрелочными функциями вам больше не нужно прибегать к хаку that = this перед вызовом функции внутри функции.
Подробное объяснение
Краткость
Стрелочные функции во многих отношениях более краткие, чем обычные. Рассмотрим все возможные случаи:
- Явный и неявный возврат.
Функция может явно возвращать результат с использованием ключевого слова return .
При обычном способе написания функций возврат всегда был явным. Со стрелочными функциями его можно сделать неявным. Это значит, что для возврата значения не нужно использовать ключевое слово return .
Поскольку здесь нет ничего, кроме возвращаемого значения, можно вернуть значение без явного указания.
Для этого нам просто нужно убрать фигурные скобки и ключевое слово return . Поэтому это и называется неявным возвратом: ключевого слова return нет, но функция все равно вернет x * 2 .
Примечание: Если ваша функция не возвращает никакого значения (с побочными эффектами), то в ней нет ни явного, ни неявного возврата.
Кроме того, если вы хотите неявно вернуть объект, вы должны заключить его в круглые скобки, так как иначе он будет конфликтовать с фигурными скобками блоков:
- Только один аргумент.
Если ваша функция принимает только один аргумент, то скобки вокруг него можно опустить. Возвращаясь к функции double в коде выше:
Скобки вокруг этого аргумента можно опустить:
- Без аргументов.
Когда стрелочная функция вообще не принимает никаких аргументов, нужно использовать пустые круглые скобки, иначе синтаксис будет неправильным.
Использование this
Чтобы понять эту тонкость поведения стрелочных функций, нужно понимать, как this ведёт себя в JavaScript.
Внутри стрелочной функции значение this равно значению this внешнего окружения. Это значит, что стрелочная функция не создает новый this , а получает его из окружения.
Без использования стрелочных функций для получения доступа к переменной через this в функции, вложенной в другую функцию, придется использовать хак that = this или self = this .
Вот, к примеру, использование функции setTimeout внутри функции myFunc :
Но в случае стрелочных функций this берется из окружения:
Полезные ресурсы
Значение аргументов функции по умолчанию
Начиная с обновления JavaScript ES2015, аргументам функции можно присваивать значения по умолчанию, используя следующий синтаксис:
Значения по умолчанию применяются только в двух случаях:
- значение не передано;
- передано значение undefined .
Другими словами, если передать в функцию параметр null , то параметр по умолчанию не применится.
Примечание: Присваивать значение по умолчанию можно в том числе и при работе с деструктурированными параметрами (см. пример в следующем понятии).
Дополнительные материалы
Деструктуризация объектов и массивов
Деструктуризация — это удобный способ создания новых переменных путем извлечения значений из объектов или массивов.
На практике деструктуризацию можно использовать, чтобы присваивать переменным разбитые на части параметры функции или this.props в React-проектах.
Объяснение с помощью примера кода
- Объект.
Давайте использовать во всех примерах следующий объект:
С деструктуризацией всё поместится в одну строку:
Примечание: В const < age >= person; скобки после ключевого слова const используются не для обозначения объекта или блока. Это синтаксис деструктуризации.
- Параметры функции.
Деструктуризация часто используется для разбиения параметров функции на части.
Если деструктурировать параметр person , то функция получится куда более лаконичной:
Ещё удобнее использовать деструктуризацию со стрелочными функциями:
- Массив.
Давайте рассмотрим следующий массив:
С использованием деструктуризации:
Полезные ресурсы
Методы массивов — map / filter / reduce
map , filter и reduce — это методы массивов, пришедшие из парадигмы функционального программирования.
- Array.prototype.map() принимает массив, каким-нибудь образом преобразует его элементы и возвращает новый массив трансформированных элементов.
- Array.prototype.filter() принимает массив, просматривает каждый элемент и решает, убрать его или оставить. Возвращает массив оставшихся значений.
- Array.prototype.reduce() принимает массив и вычисляет на основе его элементов какое-то единое значение, которое и возвращает.
Я рекомендую пользоваться ими как можно чаще, следуя принципам функционального программирования, потому что они лаконичные, элегантные и их можно комбинировать.
Вооружившись этими тремя методами, вы можете обойтись без использования for и forEach в большинстве ситуаций. Когда в следующий раз соберётесь запустить цикл for , попробуйте решить задачу с помощью map , filter и reduce . Поначалу это будет трудно, потому что вам придётся научиться мыслить по-другому, но, разобравшись один раз, вы сможете применять эти методы без особых усилий.
Пример кода
Давайте посчитаем сумму баллов всех студентов, которые набрали больше 10 баллов, используя map , filter и reduce :
Объяснение
Давайте использовать в качестве примера следующий массив:
Array.prototype.map()
Что же здесь происходит? Мы применяем к массиву numbers метод map , который взаимодействует с каждым элементом массива, передавая его в нашу функцию. Цель функции — произвести расчёт и вернуть новое значение, чтобы map мог подставить его вместо переданного в функцию.
Давайте даже вынесем функцию из массива, чтобы было понятнее, что происходит:
numbers.map(doubleN) создаёт [doubleN(0), doubleN(1), doubleN(2), doubleN(3), doubleN(4), doubleN(5), doubleN(6)] , что равняется [0, 2, 4, 6, 8, 10, 12] .
Примечание: Если вам не нужно возвращать новый массив и вы просто хотите перебрать существующий массив, совершая с его элементами некоторые действия, можете просто использовать for / forEach вместо метода map .
Array.prototype.filter()
Мы применяем filter к массиву numbers . Метод filter взаимодействует с каждым элементом массива и передаёт его в нашу функцию. Функция возвращает булево значение, определяющее, будет ли элемент сохранён в массиве. Затем filter возвращает массив отфильтрованных значений.
Array.prototype.reduce()
Цель метода reduce заключается в том, чтобы вычислить на основе массива какое-то одно значение. Какие именно вычисления метод произведет с элементами, зависит только от вас.
Так же, как методы .map и .filter , метод .reduce применяется к массиву и в качестве первого параметра принимает функцию.
На этот раз, впрочем, кое-что изменилось:
- .reduce принимает два параметра.
Первый параметр — это функция, которая будет вызываться на каждом шаге цикла.
Второй параметр — это значение аккумулирующей переменной ( acc в нашем случае) на первом шаге цикла (чтобы разобраться, читайте далее).
- Параметры функции.
Функция, которую вы передаёте в качестве первого параметра метода .reduce , принимает два аргумента. Первый аргумент — это аккумулирующая переменная ( acc в нашем примере), второй аргумент — текущий элемент.
Аккумулирующая переменная равна значению, возвращённому нашей функцией на предыдущем шаге цикла. В самом начале каждого цикла acc равна значению, которое было передано в качестве второго параметра .reduce .
На первом шаге
acc = 0 , потому что мы передали 0 в качестве второго параметра метода reduce .
n = 0 — первый элемент массива number .
Функция возвращает acc + n –> 0 + 0 –> 0.
На втором шаге
acc = 0 , потому что это значение функция вернула на предыдущем шаге.
n = 1 — второй элемент массива number .
Функция возвращает acc + n –> 0 + 1 –> 1.
На третьем шаге
acc = 1 , потому что это значение функция вернула на предыдущем шаге.
n = 2 — третий элемент массива number .
Функция возвращает acc + n –> 1 + 2 –> 3.
На четвертом шаге
acc = 3 , потому что это значение функция вернула на предыдущем шаге.
n = 3 — четвёртый элемент массива number .
Функция возвращает acc + n –> 3 + 3 –> 6.
На последнем шаге
acc = 15 , потому что это значение функция вернула на предыдущем шаге.
n = 6 — последний элемент массива number .
Функция возвращает acc + n –> 15 + 6 –> 21.
Поскольку это был последний шаг, .reduce возвращает 21 .
Дополнительные материалы
Оператор расширения .
Оператор расширения . , появившийся в ES2015, предназначен для развертывания итерируемых объектов (например, массивов) в тех местах, где можно поместить несколько элементов.
Пример кода
Объяснение
В итерируемых объектах (например, массивах)
Если у нас есть два следующих массива:
Первый элемент массива arr2 — это массив, потому что arr1 напрямую вставляется в arr2 . Но мы хотим, чтобы arr2 состоял только из букв. Чтобы добиться этого, мы можем развернуть элементы массива arr1 в массиве arr2 .
С использованием оператора расширения:
Оставшиеся аргументы функции
Для объединения аргументов можно использовать оператор оставшихся аргументов функции. Этот оператор позволяет представить любое число аргументов в виде массива, элементы которого можно перебрать при помощи цикла. Вообще, к каждой функции уже привязан объект arguments — массив, состоящий из всех аргументов, переданных функции.
Но давайте представим, что мы хотим, чтобы наша функция создала нового студента со своими оценками и средним баллом. Удобнее будет записать первые два аргумента в две отдельные переменные, а все оценки поместить в массив, который можно перебирать.
Именно это позволяет нам сделать оператор оставшихся аргументов!
Примечание: createStudent — плохая функция, потому что мы не проверяем, существует ли grades.length и отличается ли от 0. Но так функцию легче прочитать, поэтому я не учитывал эти случаи.
Расширение свойств объектов
Чтобы понять эту часть, рекомендую прочитать предыдущие объяснения о применении оператора оставшихся аргументов к итерируемым объектам и параметрам функций.
Дополнительные материалы
Сокращенная запись свойств объектов
При записи переменной в свойство объекта, если у переменной то же имя, что и у свойства, можно сделать следующее:
Объяснение
Раньше (до ES2015), если вы хотели при объявлении нового литерала объекта использовать переменные в качестве его свойств, вам пришлось бы писать подобный код:
Как видите, приходится повторять одно и то же, потому что имена свойств объекта совпадают с именами переменных, которые вы хотите записать в эти свойства.
С ES2015, если имя переменной совпадает с именем свойства, можно использовать такую сокращенную запись:
Дополнительные материалы
Промисы
Промис (promise) — это объект, который может быть синхронно возвращён из асинхронной функции (Ссылка).
Промисы могут использоваться, чтобы избежать «ада обратных вызовов», и они всё чаще и чаще используются в современных JavaScript-проектах.
Пример кода
Пояснение
Когда вы делаете AJAX-запрос, ответ будет несинхронным, так как вы запрашиваете ресурс, на обработку которого требуется некоторое время. Ответ может быть вообще не получен, если запрашиваемый ресурс недоступен по какой-то причине (404).
Чтобы избежать таких ситуаций, в ES2015 были добавлены промисы. Промисы могут иметь 3 различных состояния:
- выполняется;
- выполнено;
- отклонено.
Предположим, мы хотим использовать промисы для обработки AJAX-запроса для получения ресурса X.
Создание промиса
Сначала создадим промис. Будем использовать GET-метод jQuery для создания AJAX-запроса к ресурсу X.
Как видно из рассмотренного примера, объект Promise принимает функцию-исполнитель, в свою очередь принимающую два параметра: resolve и reject . Эти параметры — функции, которые при вызове изменяют состояние промиса со значения выполняется на выполнено или отклонено соответственно.
Промис находится в состоянии выполняется после создания экземпляра, и его функция-исполнитель выполняется немедленно. Как только одна из функций выполнено или отклонено вызвана в функции-исполнителе, промис вызовет связанные с ним обработчики.
Использование обработчиков промисов
Чтобы получить результат (или ошибку) промиса, нужно назначить ему обработчики следующим образом:
Если вызов прошёл успешно, вызывается resolve и выполняется функция, переданная в метод .then .
Если вызов не прошёл, вызывается reject и выполняется функция, переданная в .catch .
Примечание: Если промис уже выполнен или отклонён на момент назначения соответствующего обработчика, обработчик всё равно будет вызван. Так что между выполнением асинхронной операции и назначением обработчиков не возникает состояние гонки. (Ссылка: MDN)
Дополнительные материалы
Шаблонные строки
Шаблонные строки — это конструкции, позволяющие использовать вставку, или интерполяцию выражений, в однострочных и многострочных строках.
Другими словами, это новый синтаксис записи строк, с которым удобно использовать любые выражения JavaScript (например, переменные).
Пример кода
Дополнительные материалы
Тегированные шаблонные строки
Шаблонные теги — это функции, которые могут быть префиксом к шаблонной строке. Когда функция вызывается таким образом, первый параметр представляет собой массив строк, которые выводятся между интерполированными переменными, а последующие параметры — значения выражений, вставленных в строку. Для захвата всех этих значений используйте оператор расширения . . (Ссылка: MDN).
Примечание: Известная библиотека, которая называется стилизованные компоненты, основана на этой возможности.
Ниже приведен пример работы тегированных шаблонных строк:
Более интересный пример:
Дополнительные материалы
Импорт / экспорт
Модули в ES6 используются для получения доступа к переменным и функциям из других модулей (файлов с кодом), причем экспорт этих переменных и функций должен быть четко обозначен в исходном модуле.
Крайне рекомендую почитать ресурсы MDN об экспорте/импорте (см. Дополнительные материалы ниже), в них содержится четкая и полная информация.
Объяснение с примером кода
Именованный экспорт
Именованный экспорт используется для экспорта нескольких значений из модуля.
Примечание: Вы можете именовать экспорт только объектами первого класса, у которых есть имя.
Хотя именованный импорт выглядит как деструктуризация, это не одно и то же. Кроме того, именованный импорт имеет другой синтаксис, не поддерживает значения по умолчанию и глубокую деструктуризацию.
Кроме того, можно создавать псевдонимы, но их синтаксис будет отличаться от синтаксиса, используемого при деструктуризации:
Импорт / экспорт по умолчанию
Что касается экспорта по умолчанию, то для каждого модуля (файла) может быть только один экспорт. Экспортом по умолчанию может быть функция, класс, объект или что-то еще. Это значение считается «основным», поскольку его будет проще всего импортировать. Ссылка: MDN.
Дополнительные материалы
this в JavaScript
Оператор this в JavaScript ведет себя не так, как в других языках. В большинстве случаев он определяется тем, как вызвана функция (Ссылка: MDN).
Это сложное понятие с множеством тонкостей, так что я крайне рекомендую вам тщательно изучить приведенные ниже Дополнительные материалы. Я покажу вам, как сам лично определяю, чему равно this . Этому меня научила вот эта статья Yehuda Katz.
Дополнительные материалы
Класс
JavaScript — это язык, основанный на прототипах (в то время как, например, Java — язык, основанный на классах). В обновлении ES6 представлены классы JavaScript, которые являются синтаксическим сахаром для наследования на основе прототипов, а не новой моделью наследования на основе классов (Ссылка).
Если вы знакомы с классами в других языках, слово «класс» может ввести вас в заблуждение. Постарайтесь не делать предположений о работе классов в JavaScript на основе других языков. Считайте это совершенно другим понятием.
Поскольку этот документ не является попыткой научить вас языку с нуля, я надеюсь, что вы знаете, что такое прототипы и как они себя ведут. Если нет, смотрите дополнительные материалы после примеров.
Примеры
До ES6, синтаксис на основе прототипов:
Начиная с ES6, синтаксис на основе классов:
Дополнительные материалы
Для понимания прототипов:
Для понимания классов:
Ключевые слова Extends и super
Ключевое слово extends используется в объявлении класса или в выражениях класса для создания дочернего класса (Ссылка: MDN). Дочерний класс наследует все свойства родительского класса и дополнительно может добавлять новые свойства или изменять унаследованные.
Ключевое слово super используется для вызова функций родителя объекта, включая его конструктор.
- В конструкторе ключевое слово super должно использоваться раньше, чем ключевое слово this .
- Вызов super() вызывает конструктор родительского класса. Если вы хотите передать какие-то аргументы из конструктора класса в конструктор родительского класса, то нужно вызывать функцию следующим образом: super(arguments) .
- Если у родительского класса есть метод X (даже статический), для его вызова в дочернем классе можно использовать super.X() .
Пример кода
Примечание: Если бы мы попытались использовать this перед вызовом super() в классе Square, произошёл бы ReferenceError:
Дополнительные материалы
Async Await
Помимо Промисов вам может встретиться еще один синтаксис для обработки асинхронного кода — async / await .
Цель функций async / await — упростить синхронное использование промисов и выполнить какое-либо действие над группой промисов. Точно так же, как промисы похожи на структурированные функции обратного вызова, async / await похожи на комбинацию генераторов и промисов. (Ссылка: MDN)
Примечание: перед тем как пытаться понять async / await , вы должны понимать, что такое промисы и как они работают, поскольку async / await основаны на промисах.
Примечание 2: await должен использоваться в async функции, что означает, что вы не можете использовать await на верхнем уровне вашего кода, так как он не находится внутри async-функции.
Пример кода
Объяснение с помощью примера кода
async / await построены на промисах, но позволяют использовать более императивный стиль кода.
Оператор async объявляет функцию как асинхронную, и данная функция всегда будет возвращать промис. В async-функции можно использовать оператор await для приостановки выполнения до тех пор, пока возвращаемый промис либо выполнится, либо будет отклонен.
Когда будет достигнут оператор return async-функции, промис выполняется с возвращаемым значением. Если внутри async-функции генерируется ошибка, состояние промиса изменится на rejected . Если async-функция не возвращает никакого значения, промис всё равно будет возвращен и выполнится без значения, когда выполнение async-функции будет завершено.
Оператор await используется для ожидания выполнения Промиса и может быть использован только в теле async-функции. При этом выполнение кода приостанавливается, пока не будет выполнен промис.
Примечание: fetch — это функция, возвращающая промис, который позволяет выполнить AJAX-запрос.
Давайте сначала посмотрим, как мы можем получить пользователя github с помощью промисов:
Вот эквивалент с использованием async / await :
Синтаксис async / await особенно удобен для построения цепочек взаимозависимых промисов.
Например, вам нужно получить токен для того, чтобы получить публикацию в блоге из базы данных, а затем информацию об авторе.
Примечание: Выражение await должно быть заключено в круглые скобки для вызова методов и свойств разрешенных значений в одной строке.
Обработка ошибок
Если мы не добавим блок try / catch вокруг выражения await , неперехваченные исключения — неважно, были ли они выброшены в теле вашей async-функции или во время ожидания выполнения await — отклонят промис, возвращенный из async-функции. Использование состояния throw в асинхронной функции — то же самое, что возврат промиса, который был отклонен. (Ссылка: PonyFoo).
Примечание: Промисы ведут себя так же!
С помощью промисов вот как бы мы обработали ошибки:
Эквивалент с использованием async / await :
Дополнительные материалы
Истина / Ложь
В JavaScript «истинность» или «ложность» значения определяется при вычислении этого значения в булевом контексте. Примером булева контекста может быть вычисление в условии if .
Любое значение будет приведено к true (истина), кроме:
- false (ложь);
- 0 ;
- «» (пустая строка);
- null ;
- undefined ;
- NaN .
Вот примеры булева контекста:
-
значение условия if .
Значение myVar может быть любым объектом первого класса (переменная, функция, логическое значение), но оно будет преобразовано в логическое значение, поскольку вычисляется в булевом контексте.
- После логического оператора NOT ! .
Этот оператор возвращает значение «ложь», если его единственный операнд может быть преобразован к значению «истина»; иначе он возвращает значение «истина».
- Конструктор объектов типа Boolean .
- Тернарный оператор.
Значение myVar вычисляется в булевом контексте.
Будьте внимательны при сравнении двух значений. Значения объектов (которые должны быть приведены к истине), не приводятся к булеву типу, а приводятся к примитивному типу в соответствии со спецификацией. Внутри, когда объект сравнивается с булевым значением, например, [] == true , выполняется [].toString() == true , происходит следующее:
Дополнительные материалы
Анаморфизмы и катаморфизмы
Анаморфизмы
Анаморфизмы — это фунции, которые отображают некоторый объект на более сложную структуру, содержащую тип объекта. Это процесс разворачивания простой структуры в более сложную.
Рассмотрим разворачивание целого числа в список целых чисел. Целое число — наш изначальный объект, а список целых чисел — более сложная структура.
Пример кода
Катаморфизмы
Катаморфизмы противоположны анаморфизмам: они берут объекты более сложной структуры и складывают их в более простые структуры.
Рассмотрим следующий пример функции product , которая принимает список целых чисел и возвращает простое целое число.
Пример кода
Дополнительные материалы
Генераторы
Другой способ написания функции downToOne — использование генератора. Чтобы создать объект типа Generator , нужно использовать объявление function * . Генераторы — это функции, выполнение которых может быть прервано, а затем продолжено с тем же контекстом (привязками переменных), сохраняющимся при всех вызовах.
Например, функция downToOne может быть переписана следующим образом:
Генераторы возвращают итерируемый объект. Когда вызывается метод next() итератор, она выполняется до первого выражения yield , которое указывает значение, которое должно быть возвращено из итератора или с помощью yield* , которое дегегирует выполнение другому генератору. Когда в генераторе вызывается выражение return , он будет помечать генератор как выполненный и возвращать значение из выражения return . Дальнейшие вызовы next() не будут возвращать никаких новых значений.
Пример кода
Выражение yield* позволяет генератору вызывать другую функцию-генератор во время итерации.