Грамматика и типы
В данной главе рассматриваются базовая грамматика, объявление переменных, типы данных и литералы.
Основы
JavaScript заимствует большую часть синтаксиса из Java, но также испытал влияние таких языков, как Awk, Perl и Python.
JavaScript чувствителен к регистру и использует кодировку символов Unicode. Например, слово Früh («рано» по-немецки) может использоваться в качестве имени переменной.
Но, переменная früh не то же самое что Früh потому что JavaScript чувствителен к регистру.
В JavaScript инструкции называются statements и разделяются точкой с запятой (;). Пробел (space), табуляция (tab) и перевод строки (newline) называются пробельными символами (whitespace). Исходный текст скриптов на JavaScript сканируется слева направо и конвертируется в последовательность входных элементов, являющихся токенами (tokens), управляющими символами, символами конца строки, комментариями или пробельными символами. ECMAScript также определяет некоторые ключевые слова и литералы и устанавливает правила для автоматической вставки точек с запятой (ASI), чтобы обозначить конец инструкций (statements). Однако, рекомендуется всегда ставить точку с запятой в конце каждой инструкции вручную, чтобы избежать побочных эффектов. Чтобы получить более подробную информацию, прочитайте Lexical Grammar.
Комментарии
Синтаксис комментариев является таким же, как и в C++ и во многих других языках:
Объявления
В JavaScript существует три вида объявлений:
Объявляет переменную, инициализация переменной значением является необязательной.
Объявляет локальную переменную в области видимости блока, инициализация переменной значением является необязательной.
Объявляет именованную константу, доступную только для чтения.
Переменные
Вы можете использовать переменные как символические имена для значений в вашем приложении. Имена переменных называются identifiers и должны соответствовать определённым правилам.
Идентификатор в JavaScript должен начинаться с буквы, нижнего подчёркивания (_) или знака доллара ($); последующие символы могут также быть цифрами (0-9). Поскольку JavaScript чувствителен к регистру, буквы включают символы от «A» до «Z» (верхний регистр) и символы от «a» до «z» (нижний регистр).
Вы можете использовать в идентификаторах буквы ISO 8859-1 или Unicode, например, å или ü. Вы также можете использовать управляющие последовательности Unicode как символы в идентификаторах.
Некоторые примеры корректных имён: Number_hits , temp99 , _name .
Объявление переменных
Вы можете объявить переменную тремя способами:
- Используя ключевое слово var . Например, var x = 42 . Данный синтаксис может быть использован для объявления как локальных, так и глобальных переменных.
- Просто присвоить переменной значение. Например, x = 42 . Переменные, объявленные данным способом, являются глобальными. Такое объявление генерирует строгое предупреждение (strict mode). Не рекомендуется использовать данный способ.
- Используя ключевое слово let . Например, let y = 13 . Данный синтаксис может быть использован для объявления локальной переменной в области видимости блока.
Присваивание значений
Переменная, объявленная через var или let без присвоения начального значения, имеет значение undefined .
При попытке доступа к необъявленной переменной или переменной до её объявления будет выброшено исключение ReferenceError :
Вы можете использовать undefined , чтобы определить, имеет ли переменная значение. В следующем примере переменной input не присвоено значение, и оператор if будет вычислен как true :
Значение undefined ведёт себя как false , когда используется в логическом контексте. Например, следующий код выполняет функцию myFunction , т.к. элемент myArray не определён:
Значение undefined конвертируется в NaN , когда используется в числовом контексте:
Значение null ведёт себя как 0 в числовом контексте и как false в логическом контексте:
Область видимости переменных
Когда вы объявляете переменную вне функции, то такая переменная называется глобальной переменной, т.к. доступна любому коду в текущем документе. Когда вы объявляете переменную внутри функции, то такая переменная называется локальной переменной, т.к. доступна только внутри данной функции.
До ECMAScript 6 в JavaScript отсутствовала область видимости блока; переменная, объявленная внутри блока, является локальной для _функции _(или глобальной области видимости), внутри которой находится данный блок. Например, следующий код выведет значение 5, т.к. областью видимости переменной x является функция (или глобальный контекст), внутри которой объявлена переменная x , а не блок, которым в данном случае является оператор if :
Такое поведение меняется, если используется оператор let , введённый в ECMAScript 6:
Поднятие переменных
Другим необычным свойством переменных в JavaScript является то, что можно сослаться на переменную, которая объявляется позже, и не получить при этом исключения. Эта концепция известна как поднятие (hoisting) переменных; переменные в JavaScript поднимаются в самое начало функции или выражения. Однако, переменные, которые ещё не были инициализированы, возвратят значение undefined :
Приведённые выше примеры будут интерпретироваться так же, как:
Из-за поднятия переменных, все операторы var в функции следует размещать настолько близко к началу функции, насколько это возможно. Следование этому правилу улучшает ясность кода.
В ECMAScript 2015, let (const) не будет подниматься вверх блока. Однако, ссылки на переменную в блоке до объявления переменной вызовут ReferenceError . Переменная во «временной мёртвой зоне» в начале блока, до объявления.
Поднятие функций
Для функций: только определения функций поднимаются наверх, но не функции, определённые через выражения.
Глобальные переменные
Глобальные переменные на самом деле являются свойствами глобального объекта. На веб-страницах глобальным объектом является window , поэтому вы можете устанавливать глобальные переменные и обращаться к ним, используя синтаксис window.variable :
Следовательно, вы можете обращаться к глобальным переменным, объявленным в одном объекте window или frame из другого объекта window или frame, указав имя window или frame. Например, если переменная phoneNumber объявлена в документе, то вы можете сослаться на эту переменную из iframe как parent.phoneNumber .
Константы
Вы можете создать именованную константу, доступную только для чтения, используя ключевое слово const . Синтаксис идентификатора константы является таким же, как и у идентификатора переменной: он должен начинаться с буквы, нижнего подчёркивания или знака $ и может содержать буквы, цифры или нижнее подчёркивание.
Нельзя изменить значение константы через присваивание или повторное объявление во время выполнения скрипта. Значение должно быть указано при инициализации.
Правила, касающиеся области видимости, для констант являются такими же, как и для переменных, объявленных через let . Если ключевое слово const не указано, то идентификатор будет являться переменной.
Нельзя объявить константу с таким же именем, как у функции или переменной в одной области видимости. Следующие примеры выбросят исключение TypeError :
Однако, атрибуты объектов не защищены, так что следующее выражение выполнится без проблем
Структуры и типы данных
Типы данных
Последний стандарт ECMAScript определяет семь типов данных:
-
Шесть типов данных, которые являются примитивами:
- Десятичный целочисленный литерал состоит из последовательности цифр без ведущего нуля.
- Ведущий ноль в целочисленном литерале указывает на то, что он записан в восьмеричной системе счисления. Восьмеричные целые числа состоят только из цифр 0-7.
- Ведущие символы 0x (или 0X) указывают на то, что число шестнадцатеричное. Шестнадцатеричные целые числа могут состоять из цифр 0-9 и букв a-f и A-F.
- Ведущие символы 0b (или 0B) указывают на то, что число двоичное. Двоичные числа могут включать в себя только цифры 0 и 1.
- Десятичное целое число, которое может иметь знак (символ «+» или «-«, стоящий перед числом),
- Десятичная точка («.»),
- Дробная часть (другое десятичное число),
- Экспонента.
- Интернет-магазин – информация может включать продаваемые товары и корзину покупок.
- Чат – информация может включать пользователей, сообщения и многое другое.
- Имя переменной должно содержать только буквы, цифры или символы $ и _ .
- Первый символ не должен быть цифрой.
- COLOR_ORANGE гораздо легче запомнить, чем "#FF7F00" .
- Гораздо легче допустить ошибку при вводе "#FF7F00" , чем при вводе COLOR_ORANGE .
- При чтении кода COLOR_ORANGE намного понятнее, чем #FF7F00 .
- Используйте легко читаемые имена, такие как userName или shoppingCart .
- Избегайте использования аббревиатур или коротких имён, таких как a , b , c , за исключением тех случаев, когда вы точно знаете, что так нужно.
- Делайте имена максимально описательными и лаконичными. Примеры плохих имён: data и value . Такие имена ничего не говорят. Их можно использовать только в том случае, если из контекста кода очевидно, какие данные хранит переменная.
- Договоритесь с вашей командой об используемых терминах. Если посетитель сайта называется «user», тогда мы должны называть связанные с ним переменные currentUser или newUser , а не, к примеру, currentVisitor или newManInTown .
- let – это современный способ объявления.
- var – это устаревший способ объявления. Обычно мы вообще не используем его, но мы рассмотрим тонкие отличия от let в главе Устаревшее ключевое слово "var" на случай, если это всё-таки вам понадобится.
- const – похоже на let , но значение переменной не может изменяться.
- Объявите две переменные: admin и name .
- Запишите строку "Джон" в переменную name .
- Скопируйте значение из переменной name в admin .
- Выведите на экран значение admin , используя функцию alert (должна показать «Джон»).
- number (число)
- string (строка)
- boolean (логическое значение)
- null (специальное значение null )
- undefined (специальное значение undefined )
- symbol (символ, используется в особых случаях, появился в ES6)
- имеют в качестве области видимости блок;
- недоступны до объявления;
- не могут быть повторно объявлены в той же области видимости.
- имеют в качестве области видимости блок;
- недоступны до объявления;
- не могут быть повторно объявлены в той же области видимости;
- не могут быть переопределены.
- краткость;
- this берется из окружающего контекста;
- неявный возврат.
- Краткость и неявный возврат.
- Явный и неявный возврат.
- Только один аргумент.
- Без аргументов.
- значение не передано;
- передано значение undefined .
- Объект.
- Параметры функции.
- Массив.
- Array.prototype.map() принимает массив, каким-нибудь образом преобразует его элементы и возвращает новый массив трансформированных элементов.
- Array.prototype.filter() принимает массив, просматривает каждый элемент и решает, убрать его или оставить. Возвращает массив оставшихся значений.
- Array.prototype.reduce() принимает массив и вычисляет на основе его элементов какое-то единое значение, которое и возвращает.
- .reduce принимает два параметра.
- Параметры функции.
- выполняется;
- выполнено;
- отклонено.
- В конструкторе ключевое слово super должно использоваться раньше, чем ключевое слово this .
- Вызов super() вызывает конструктор родительского класса. Если вы хотите передать какие-то аргументы из конструктора класса в конструктор родительского класса, то нужно вызывать функцию следующим образом: super(arguments) .
- Если у родительского класса есть метод X (даже статический), для его вызова в дочернем классе можно использовать super.X() .
- false (ложь);
- 0 ;
- «» (пустая строка);
- null ;
- undefined ;
- NaN .
- После логического оператора NOT ! .
- Конструктор объектов типа Boolean .
- Тернарный оператор.
-
. true и false . . Специальное ключевое слово, обозначающее нулевое или «пустое» значение. Поскольку JavaScript чувствителен к регистру, null не то же самое, что Null , NULL или любой другой вариант. . Свойство глобального объекта; переменная, не имеющая присвоенного значения, обладает типом undefined . . 42 или 3.14159 . . «Howdy». (ECMAScript 6)
Хотя типов данных относительно немного, но они позволяют вам выполнять полезные функции в ваших приложениях. Объекты и функции являются другими фундаментальными элементами языка. Вы можете думать об объектах как об именованных контейнерах для значений и о функциях как о процедурах, которые ваше приложение может исполнять.
Преобразование типов данных
JavaScript — это динамически типизированный язык. Это означает, что вам не нужно указывать тип данных переменной, когда вы её объявляете, типы данных преобразуются автоматически по мере необходимости во время выполнения скрипта. Так, например, вы можете определить переменную следующим образом:
А позже вы можете присвоить этой переменной строковое значение, например:
Поскольку JavaScript является динамически типизированным, это присваивание не вызовет сообщения об ошибке.
В выражениях, включающих числовые и строковые значения с оператором + , JavaScript преобразует числовые значения в строковые. Например:
В выражениях с другими операторами JavaScript не преобразует числовые значения в строковые. Например:
Преобразование строк в числа
В том случае, если значение, представляющее число, хранится в памяти как строка, можно использовать методы для преобразования строк в числа:
parseInt преобразует строку в целочисленное значение. Хорошей практикой является всегда указывать основание системы счисления (параметр radix ).
Альтернативным способом для получения числа из строки является использование оператора «унарный плюс»:
Литералы
Литералы используются для представления значений в JavaScript. Они являются фиксированными значениями, а не переменными. В данной секции рассматриваются следующие типы литералов:
Литерал массива
Литерал массива — это список из нуля или более выражений, каждое из которых представляет элемент массива, заключённый в квадратные скобки ( [] ). Когда вы создаёте массив, используя литерал массива, он инициализируется с помощью переданных значений, которые будут являться его элементами, длина массива будет равна числу переданных аргументов.
В следующем примере создаётся массив coffees с тремя элементам и длиной, равной трём:
Примечание: Обратите внимание на то, что литерал массива является инициализатором объекта. Чтобы получить более подробную информацию, прочитайте Использование инициализаторов объекта.
Если массив создаётся с помощью литерала в скрипте верхнего уровня, то JavaScript интерпретирует массив каждый раз, когда вычисляет выражение, содержащее литерал. Кроме того, литерал, используемый в функции, создаётся каждый раз, когда вызывается функция.
Литералы массива также являются объектами Array . Чтобы получить более подробную информацию, прочитайте Array и упорядоченные наборы данных.
Лишние запятые в литералах array
Не обязательно указывать все элементы в литерале array. Если вы поставите две запятые подряд, то пропущенные элементы будут иметь значение undefined . Например:
У этого массива есть 2 элемента со значениям и один пустой ( fish[0] — «Lion», fish[1] — undefined , а fish[2] — «Angel»).
Если вы поставите запятую в конце списка элементов, то она будет проигнорирована. В следующем примере, длина массива равна 3. Нет myList[3] . Все другие запятые в списке говорят о новом элементе.
Примечание: Лишние запятые могут вызывать ошибки в старых версиях браузеров, поэтому лучше избегать их использования.
В следующем примере длина массива равна четырём, элементы myList[0] и myList[2] имеют значение undefined :
В следующем примере длина массива равна четырём, элементы myList[1] и myList[3] имеют значение undefined . Игнорируется только последняя запятая.
Понимание поведения лишних запятых важно для понимания JavaScript как языка. Однако, когда будете писать свой собственный код, то имейте в виду, что явное объявление отсутствующих элементов как undefined улучшает ясность кода и лёгкость его поддержки.
Логические литералы
Логический (Boolean) тип имеет два литеральных значения: true и false .
Не путайте примитивные логические значения true и false со значениями true и false объекта Boolean. Объект Boolean является объектом-обёрткой над примитивом логического типа. Чтобы получить более подробную информацию, прочитайте Boolean .
Литерал целого числа
Целые числа могут быть записаны в десятичной, шестнадцатеричной, восьмеричной и двоичной системах счисления.
Несколько примеров целочисленных литералов:
Литерал числа с плавающей точкой
Числа с плавающей точкой могут состоять из следующих частей:
Экспонента состоит из символа «e» или «E», за которым следует целое число, которое может иметь знак. Число с плавающей точкой должно состоять по крайней мере из одной цифры и либо десятичной точки, либо символа «e» (или «E»).
В более сжатой форме синтаксис выглядит следующим образом:
Литерал объекта
Литерал объекта — это список из нуля или более пар, состоящих из имён свойств и связанных с ними значений, заключённый в фигурные скобки ( <> ). Вам не следует использовать литерал объекта в начале выражения, т.к. это приведёт к ошибке или к поведению, которого вы не ожидаете, потому что символ «<" будет интерпретироваться как начало блока.
В следующем примере свойству myCar объекта car присваивается строка «Saturn» , свойству getCar — результат вызова функции CarTypes(«Honda») , свойству special — значение переменной Sales :
Кроме того, вы можете использовать числовой или строковой литералы в именах свойств или вкладывать один объект в другой. Например:
Именем свойства объекта может быть любая строка, в том числе пустая строка. Если имя свойства не является корректным JavaScript идентификатором, то оно должно быть заключено в кавычки. Для обращения к таким именам следует использовать квадратные скобки ( [] ), а не точку ( . ):
В ES2015 литералы объектов расширены до поддержки установки прототипа в конструкции короткой записи для foo: задание foo , определение методов, создание супер вызовов и вычисление имён свойств в выражениях. Вместе, они делают похожими объектные литералы и объявления классов, а также позволяют объектному дизайну получать выгоду одинаковых возможностей.
Обратите внимание на следующий пример:
RegExp литерал
Литерал regexp — шаблон между слешами. Следующий пример литерал regex:
Строковый литерал
Строковый литерал — это ноль или более символов, заключённых в двойные ( » ) или одинарные ( ‘ ) кавычки. Строка должна быть ограничена кавычками одного типа, т.е. либо обе одинарные, либо обе двойные. Например:
Вы можете вызвать любой из методов объекта String для строкового литерала: JavaScript автоматически преобразует строковой литерал во временный объект String , вызовет метод, а затем уничтожит временный объект String . Вы также можете использовать свойство String.length со строковым литералом:
В ES2015 также доступны шаблоны строк. Шаблоны строк представляют собой синтаксический сахар для конструирования строк. Это похоже на возможности интерполяции строк в Perl, Python и других. Дополнительно, может быть добавлен тег, позволяющий настраивать конструирование строк, избегая атак внедрения и построения структур данных высокого уровня из содержимого строки.
Вам следует использовать строковые литералы до тех пор, пока вам специально не понадобится объект String . Чтобы получить более подробную информацию об объекте String , прочитайте String .
Использование специальных символов в строках
Кроме обычных символов вы также можете включать специальные символы в строки.
В следующей таблице перечислены специальные символы, которые вы можете использовать.
| Символ | Значение |
|---|---|
| \b | Возврат (Backspace) |
| \f | Перевод или прогон страницы (Form feed) |
| \n | Перевод строки (New line) |
| \r | Возврат каретки (Carriage return) |
| \t | Табуляция (Tab) |
| \v | Вертикальная табуляция (Vertical tab) |
| \’ | Апостроф или одинарная кавычка |
| \» | Двойная кавычка |
| \\ | Обратная косая черта (Backslash) |
| \XXX | Символ в кодировке Latin-1, представленный тремя восьмеричными числами XXX от 0 до 377. Например, \251 (символ ©). |
| \xXX | Символ в кодировке Latin-1, представленный двумя шестнадцатеричными числами XX от 00 до FF. Например, \xA9 (символ ©). |
| \uXXXX | Символ в Unicode, представленный четырьмя шестнадцатеричными числами XXXX. Например, \u00A9 (символ ©). |
| \u | Символ в UTF-32BE. Например, \u <2F804>обозначает то же, что обычная запись \uD87E\uDC04. |
Экранирующие символы
Для символов, не перечисленных в вышеприведённой таблице, предваряющая обратная косая черта игнорируется. Такое использование не является рекомендованным (deprecated) и вам следует избегать его.
Вы можете вставить кавычку в строку, если поставите перед ней обратную косую черту. Это называется экранированием кавычек. Например:
Чтобы включить обратную косую черту в строку, перед ней нужно поставить ещё одну обратную косую черту. Например:
Вы также можете экранировать перевод строки. Обратная косая черта и перевод строки будут удалены из содержимого строки. Например:
Хотя JavaScript не поддерживает синтаксис «heredoc» (форматированный текст в одной строковой переменной), но вы можете эмулировать его, добавив перевод строки и обратную косую черту в конец каждой строки:
Дополнительная информация
Данная глава сфокусирована на базовом синтаксисе для объявлений и типов. Чтобы получить более подробную информацию о конструкциях JavaScript, прочитайте:
В следующей главе рассматриваются управляющие конструкции и обработка ошибок.
Переменные
JavaScript-приложению обычно нужно работать с информацией. Например:
Переменные используются для хранения этой информации.
Переменная
Переменная – это «именованное хранилище» для данных. Мы можем использовать переменные для хранения товаров, посетителей и других данных.
Для создания переменной в JavaScript используйте ключевое слово let .
Приведённая ниже инструкция создаёт (другими словами: объявляет или определяет) переменную с именем «message»:
Теперь можно поместить в неё данные, используя оператор присваивания = :
Строка сохраняется в области памяти, связанной с переменной. Мы можем получить к ней доступ, используя имя переменной:
Для краткости можно совместить объявление переменной и запись данных в одну строку:
Мы также можем объявить несколько переменных в одной строке:
Такой способ может показаться короче, но мы не рекомендуем его. Для лучшей читаемости объявляйте каждую переменную на новой строке.
Многострочный вариант немного длиннее, но легче для чтения:
Некоторые люди также определяют несколько переменных в таком вот многострочном стиле:
…Или даже с запятой в начале строки:
В принципе, все эти варианты работают одинаково. Так что это вопрос личного вкуса и эстетики.
В старых скриптах вы также можете найти другое ключевое слово: var вместо let :
Ключевое слово var – почти то же самое, что и let . Оно объявляет переменную, но немного по-другому, «устаревшим» способом.
Есть тонкие различия между let и var , но они пока не имеют для нас значения. Мы подробно рассмотрим их в главе Устаревшее ключевое слово "var".
Аналогия из жизни
Мы легко поймём концепцию «переменной», если представим её в виде «коробки» для данных с уникальным названием на ней.
Например, переменную message можно представить как коробку с названием "message" и значением "Hello!" внутри:
Мы можем положить любое значение в коробку.
Мы также можем изменить его столько раз, сколько захотим:
При изменении значения старые данные удаляются из переменной:
Мы также можем объявить две переменные и скопировать данные из одной в другую.
Переменная может быть объявлена только один раз.
Повторное объявление той же переменной является ошибкой:
Поэтому следует объявлять переменную только один раз и затем использовать её уже без let .
Примечательно, что существуют функциональные языки программирования, такие как Scala или Erlang, которые запрещают изменять значение переменной.
В таких языках однажды сохранённое «в коробку» значение остаётся там навсегда. Если нам нужно сохранить что-то другое, язык заставляет нас создать новую коробку (объявить новую переменную). Мы не можем использовать старую переменную.
Хотя на первый взгляд это может показаться немного странным, эти языки вполне подходят для серьёзной разработки. Более того, есть такая область, как параллельные вычисления, где это ограничение даёт определённые преимущества. Изучение такого языка (даже если вы не планируете использовать его в ближайшее время) рекомендуется для расширения кругозора.
Имена переменных
В JavaScript есть два ограничения, касающиеся имён переменных:
Примеры допустимых имён:
Если имя содержит несколько слов, обычно используется верблюжья нотация, то есть, слова следуют одно за другим, где каждое следующее слово начинается с заглавной буквы: myVeryLongName .
Самое интересное – знак доллара ‘$’ и подчёркивание ‘_’ также можно использовать в названиях. Это обычные символы, как и буквы, без какого-либо особого значения.
Эти имена являются допустимыми:
Примеры неправильных имён переменных:
Переменные с именами apple и APPLE – это две разные переменные.
Можно использовать любой язык, включая кириллицу или даже иероглифы, например:
Технически здесь нет ошибки, такие имена разрешены, но есть международная традиция использовать английский язык в именах переменных. Даже если мы пишем небольшой скрипт, у него может быть долгая жизнь впереди. Людям из других стран, возможно, придётся прочесть его не один раз.
Существует список зарезервированных слов, которые нельзя использовать в качестве имён переменных, потому что они используются самим языком.
Например: let , class , return и function зарезервированы.
Приведённый ниже код даёт синтаксическую ошибку:
Обычно нам нужно определить переменную перед её использованием. Но в старые времена было технически возможно создать переменную простым присвоением значения без использования let . Это все ещё работает, если мы не включаем use strict в наших файлах, чтобы обеспечить совместимость со старыми скриптами.
Это плохая практика, которая приводит к ошибке в строгом режиме:
Константы
Чтобы объявить константную, то есть, неизменяемую переменную, используйте const вместо let :
Переменные, объявленные с помощью const , называются «константами». Их нельзя изменить. Попытка сделать это приведёт к ошибке:
Если программист уверен, что переменная никогда не будет меняться, он может гарантировать это и наглядно донести до каждого, объявив её через const .
Константы в верхнем регистре
Широко распространена практика использования констант в качестве псевдонимов для трудно запоминаемых значений, которые известны до начала исполнения скрипта.
Названия таких констант пишутся с использованием заглавных букв и подчёркивания.
Например, сделаем константы для различных цветов в «шестнадцатеричном формате»:
Когда мы должны использовать для констант заглавные буквы, а когда называть их нормально? Давайте разберёмся и с этим.
Название «константа» просто означает, что значение переменной никогда не меняется. Но есть константы, которые известны до выполнения (например, шестнадцатеричное значение для красного цвета), а есть константы, которые вычисляются во время выполнения сценария, но не изменяются после их первоначального назначения.
Значение pageLoadTime неизвестно до загрузки страницы, поэтому её имя записано обычными, а не прописными буквами. Но это всё ещё константа, потому что она не изменяется после назначения.
Другими словами, константы с именами, записанными заглавными буквами, используются только как псевдонимы для «жёстко закодированных» значений.
Придумывайте правильные имена
В разговоре о переменных необходимо упомянуть, что есть ещё одна чрезвычайно важная вещь.
Название переменной должно иметь ясный и понятный смысл, говорить о том, какие данные в ней хранятся.
Именование переменных – это один из самых важных и сложных навыков в программировании. Быстрый взгляд на имена переменных может показать, какой код был написан новичком, а какой – опытным разработчиком.
В реальном проекте большая часть времени тратится на изменение и расширение существующей кодовой базы, а не на написание чего-то совершенно нового с нуля. Когда мы возвращаемся к коду после какого-то промежутка времени, гораздо легче найти информацию, которая хорошо размечена. Или, другими словами, когда переменные имеют хорошие имена.
Пожалуйста, потратьте время на обдумывание правильного имени переменной перед её объявлением. Делайте так, и будете вознаграждены.
Несколько хороших правил:
Звучит просто? Действительно, это так, но на практике для создания описательных и кратких имён переменных зачастую требуется подумать. Действуйте.
И последняя заметка. Есть ленивые программисты, которые вместо объявления новых переменных повторно используют существующие.
В результате их переменные похожи на коробки, в которые люди бросают разные предметы, не меняя на них этикетки. Что сейчас находится внутри коробки? Кто знает? Нам необходимо подойти поближе и проверить.
Такие программисты немного экономят на объявлении переменных, но теряют в десять раз больше при отладке.
Дополнительная переменная – это добро, а не зло.
Современные JavaScript-минификаторы и браузеры оптимизируют код достаточно хорошо, поэтому он не создаёт проблем с производительностью. Использование разных переменных для разных значений может даже помочь движку оптимизировать ваш код.
Итого
Мы можем объявить переменные для хранения данных с помощью ключевых слов var , let или const .
Переменные должны быть названы таким образом, чтобы мы могли легко понять, что у них внутри.
Задачи
Работа с переменными
В коде ниже каждая строка решения соответствует одному элементу в списке задач.
Руководство по JavaScript, часть 3: переменные, типы данных, выражения, объекты
Сегодня, в третьей части перевода руководства по JavaScript, мы поговорим о разных способах объявления переменных, о типах данных, о выражениях и об особенностях работы с объектами.
Переменные
Переменная представляет собой идентификатор, которому присвоено некое значение. К переменной можно обращаться в программе, работая таким образом с присвоенным ей значением.
Сама по себе переменная в JavaScript не содержит информацию о типе значений, которые будут в ней храниться. Это означает, что записав в переменную, например, строку, позже в неё можно записать число. Такая операция ошибки в программе не вызовет. Именно поэтому JavaScript иногда называют «нетипизированным» языком.
Прежде чем использовать переменную, её нужно объявить с использованием ключевого слова var или let . Если речь идёт о константе, применяется ключевое слово const . Объявить переменную и присвоить ей некое значение можно и не используя эти ключевые слова, но делать так не рекомендуется.
▍Ключевое слово var
До появления стандарта ES2015 использование ключевого слова var было единственным способом объявления переменных.
Если в этой конструкции опустить var , то значение будет назначено необъявленной переменной. Результат этой операции зависит от того, в каком режиме выполняется программа.
Так, если включён так называемый строгий режим (strict mode), подобное вызовет ошибку. Если строгий режим не включён, произойдёт неявное объявление переменной и она будет назначена глобальному объекту. В частности, это означает, что переменная, неявно объявленная таким образом в некоей функции, окажется доступной и после того, как функция завершит работу. Обычно же ожидается, что переменные, объявляемые в функциях, не «выходят» за их пределы. Выглядит это так:
В консоль попадёт 1 , такого поведения от программы обычно никто не ждёт, выражение bNotVar = 1 выглядит не как попытка объявления и инициализации переменной, а как попытка обратиться к переменной, находящейся во внешней по отношению к функции области видимости (это — вполне нормально). Как результат, неявное объявление переменных сбивает с толку того, кто читает код и может приводить к неожиданному поведению программ. Позже мы поговорим и о функциях, и об областях видимости, пока же постарайтесь всегда, когда смысл некоего выражения заключается в объявлении переменной, пользоваться специализированными ключевыми словами. Если в этом примере тело функции переписать в виде var bNotVar = 1 , то попытка запустить вышеприведённый фрагмент кода приведёт к появлению сообщения об ошибке (его можно увидеть в консоли браузера).
Выглядеть оно, например, может так: Uncaught ReferenceError: bNotVar is not defined . Смысл его сводится к тому, что программа не может работать с несуществующей переменной. Гораздо лучше, при первом запуске программы, увидеть такое сообщение об ошибке, чем писать непонятный код, который способен неожиданно себя вести.
Если, при объявлении переменной, её не инициализируют, не присваивают ей какого-либо значения, ей автоматически будет присвоено значение undefined .
Переменные, объявленные с помощью ключевого слова var , можно многократно объявлять снова, назначая им новые значения (но это может запутать того, кто читает код).
В одном выражении можно объявить несколько переменных:
Областью видимости переменной (scope) называют участок программы, в котором доступна (видима) эта переменная.
Переменная, инициализированная с помощью ключевого слова var за пределами какой-либо функции, назначается глобальному объекту. Она имеет глобальную область видимости и доступна из любого места программы. Если переменная объявлена с использованием ключевого слова var внутри функции, то она видна только внутри этой функции, являясь для неё локальной переменной.
Если в функции, с использованием var , объявлена переменная, имя которой совпадает с именем некоей переменной из глобальной области видимости, она «перекроет» глобальную переменную. То есть, при обращении к такой переменной внутри функции будет использоваться именно её локальный вариант.
Важно понимать, что блоки (области кода, заключённые в фигурные скобки) не создают новых областей видимости. Новая область видимости создаётся при вызове функции. Ключевое слово var имеет так называемую функциональную область видимости, а не блочную.
Если в коде функции объявлена некая переменная, она видна всему коду функции. Даже если переменная объявлена с помощью var в конце кода функции, обратиться к ней можно и в начале кода, так как в JavaScript работает механизм поднятия переменных (hoisting). Этот механизм «поднимает» объявления переменных, но не операции их инициализации. Это может стать источником путаницы, поэтому возьмите себе за правило объявлять переменные в начале функции.
▍Ключевое слово let
Ключевое слово let появилось в ES2015, его, упрощённо, можно назвать «блочной» версией var . Область видимости переменных, объявленных с помощью ключевого слова let , ограничивается блоком, оператором или выражением, в котором оно объявлено, а также вложенными блоками.
Если само слово «let» кажется не очень понятным, можно представить, что вместо него используется слово «пусть». Тогда выражение let color = ‘red’ можно перевести на английский так: «let the color be red», а на русский — так: «пусть цвет будет красным».
При использовании ключевого слова let можно избавиться от неоднозначностей, сопутствующих ключевому слову var (например, не удастся два раза, используя let , объявить одну и ту же переменную). Использование let за пределами функции, скажем, при инициализации циклов, не приводит к созданию глобальных переменных.
Например, такой код вызовет ошибку:
Если же, при инициализации цикла, счётчик i будет объявлен с использованием ключевого слова var , то i будет доступно и за пределами цикла, после того, как он завершит работу.
В наши дни, при разработке JS-программ на основе современных стандартов, вполне можно полностью отказаться от var и использовать только ключевые слова let и const .
▍Ключевое слово const
Значения переменных, объявленных с использованием ключевых слов var или let , могут быть перезаписаны. Если же вместо этих ключевых слов используется const , то объявленной и инициализированной с его помощью константе новое значение присвоить нельзя.
В данном примере константе a нельзя присвоить новое значение. Но надо отметить, что если a — это не примитивное значение, наподобие числа, а объект, использование ключевого слова const не защищает этот объект от изменений.
Когда говорят, что в переменную записан объект, на самом деле имеют в виду то, что в переменной хранится ссылка на объект. Эту вот ссылку изменить не удастся, а сам объект, к которому ведёт ссылка, можно будет изменить.
Ключевое слово const не делает объекты иммутабельными. Оно просто защищает от изменений ссылки на них, записанные в соответствующие константы. Вот как это выглядит:
В константу obj , при инициализации, записывается новый пустой объект. Попытка обращения к его свойству a , несуществующему, ошибки не вызывает. В консоль попадает undefined . После этого мы добавляем в объект новое свойство и снова пытаемся обратиться к нему. В этот раз в консоль попадает значение этого свойства — 1 . Если раскомментировать последнюю строку примера, то попытка выполнения этого кода приведёт к ошибке.
Ключевое слово const очень похоже на let , в частности, оно обладает блочной областью видимости.
В современных условиях вполне допустимо использовать для объявления всех сущностей, значения которых менять не планируется, ключевое слово const , прибегая к let только в особых случаях. Почему? Всё дело в том, что лучше всего стремиться к использованию как можно более простых из доступных конструкций для того, чтобы не усложнять программы и избегать ошибок.
Типы данных
JavaScript иногда называют «нетипизированным» языком, но это не соответствует реальному положению дел. В переменные, и правда, можно записывать значения разных типов, но типы данных в JavaScript, всё-таки, есть. В частности, речь идёт о примитивных и об объектных типах данных.
Для того чтобы определить тип данных некоего значения, можно воспользоваться оператором typeof . Он возвращает строку, указывающую тип операнда.
▍Примитивные типы данных
Вот список примитивных типов данных JavaScript:
Поговорим о наиболее часто используемых типах данных из этого списка.
Тип number
Значения типа number в JavaScript представлены в виде 64-битных чисел двойной точности с плавающей запятой.
В коде числовые литералы представлены в виде целых и дробных чисел в десятичной системе счисления. Для записи чисел можно использовать и другие способы. Например, если в начале числового литерала имеется префикс 0x — он воспринимается как число, записанное в шестнадцатеричной системе счисления. Числа можно записывать и в экспоненциальном представлении (в таких числах можно найти букву e ).
Вот примеры записи целых чисел:
Вот дробные числа.
Числовые литералы (такое поведение характерно и для некоторых других примитивных типов), при попытке обращения к ним как к объектам, автоматически, на время выполнения операции, преобразуются в соответствующие объекты, которые называют «объектными обёртками». В данном случае речь идёт об объектной обёртке Number .
Вот, например, как выглядит попытка обратиться к переменной a , в которую записан числовой литерал, как к объекту, в консоли Google Chrome.

Подсказка по объектной обёртке Number
Если, например, воспользоваться методом toString() объекта типа Number , он возвратит строковое представление числа. Выглядит соответствующая команда, которую можно выполнить в консоли браузера (да и в обычном коде) так:
Обратите внимание на двойные скобки после имени метода. Если их не поставить, система не выдаст ошибку, но, вместо ожидаемого вывода, в консоли окажется нечто, совсем не похожее на строковое представление числа 5.
Глобальный объект Number можно использовать в виде конструктора, создавая с его помощью новые числа (правда, в таком виде его практически никогда не используют), им можно пользоваться и как самостоятельной сущностью, не создавая его экземпляры (то есть — некие числа, представляемые с его помощью). Например, его свойство Number.MAX_VALUE содержит максимальное числовое значение, представимое в JavaScript.
Тип string
Значения типа string представляют собой последовательности символов. Такие значения задают в виде строковых литералов, заключённых в одинарные или двойные кавычки.
Строковые значения можно разбивать на несколько частей, используя символ обратной косой черты (backslash).
Строка может содержать так называемые escape-последовательности, интерпретируемые при выводе строки в консоль. Например, последовательность \n означает символ перевода строки. Символ обратной косой черты можно использовать и для того, чтобы добавлять кавычки в строки, заключённые в такие же кавычки. Экранирование символа кавычки с помощью \ приводит к тому, что система не воспринимает его как специальный символ.
Строки можно конкатенировать с использованием оператора + .
Шаблонные литералы
В ES2015 появились так называемые шаблонные литералы, или шаблонные строки. Они представляют собой строки, заключённые в обратные кавычки ( ` ) и обладают некоторыми интересными свойствами.
Например, в шаблонные литералы можно подставлять некие значения, являющиеся результатом вычисления JavaScript-выражений.
Использование обратных кавычек упрощает многострочную запись строковых литералов:
Тип boolean
В JavaScript есть пара зарезервированных слов, использующихся при работе с логическими значениями — это true (истина), и false (ложь). Операции сравнения, например, такие, как == , === , < , > , возвращают true или false .
Логические выражения используются в конструкциях наподобие if и while , помогая управлять ходом выполнения программы.
При этом надо отметить, что там, где ожидается значение true или false , можно использовать и другие значения, которые автоматически расцениваются языком как истинные (truthy) или ложные (falsy).
В частности, ложными значениями являются следующие:
Остальные значения являются истинными.
Тип null
В JavaScript имеется специальное значение null , которое указывает на отсутствие значения. Подобные значения используются и в других языках.
Тип undefined
Значение undefined , записанное в некую переменную, указывает на то, что эта переменная не инициализирована и значение для неё отсутствует.
Это значение автоматически возвращается из функций, результат работы которых не возвращается явно, с использованием ключевого слова return . Если функция принимает некий параметр, который, при её вызове, не указан, он также устанавливается в undefined .
Для того чтобы проверить значение на undefined , можно воспользоваться следующей конструкцией.
▍Объекты
Все значения, не являющиеся примитивными, имеют объектный тип. Речь идёт о функциях, массивах, о том, что мы называем «объектами», и о многих других сущностях. В основе всех этих типов данных лежит тип object , и они, хотя и во многом друг от друга отличаются, имеют и много общего.
Выражения
Выражения — это фрагменты кода, которые можно обработать и получить на основе проведённых вычислений некое значение. В JavaScript существует несколько категорий выражений.
Арифметические выражения
В эту категорию попадают выражения, результатом вычисления которых являются числа.
Строковые выражения
Результатом вычисления таких выражений являются строки.
Первичные выражения
В эту категорию попадают литералы, константы, ссылки на идентификаторы.
Сюда же можно отнести и некоторые ключевые слова и конструкции JavaScript.
Выражения инициализации массивов и объектов
Логические выражения
В логических выражениях используются логические операторы, результатом их вычисления оказываются логические значения.
Выражения доступа к свойствам
Эти выражения позволяют обращаться к свойствам и методам объектов.
Выражения создания объектов
Выражения объявления функций
Выражения вызова
Такие выражения используются для вызова функций или методов объектов.
Работа с объектами
Выше мы уже сталкивались с объектами, говоря об объектных литералах, о вызове их методов, о доступе к их свойствам. Здесь мы поговорим об объектах подробнее, в частности, рассмотрим механизм прототипного наследования и использование ключевого слова class .
▍Прототипное наследование
JavaScript выделяется среди современных языков программирования тем, что поддерживает прототипное наследование. Большинство же объектно-ориентированных языков используют модель наследования, основанную на классах.
У каждого JavaScript-объекта есть особое свойство ( __proto__ ), которое указывает на другой объект, являющийся его прототипом. Объект наследует свойства и методы прототипа.
Предположим, у нас имеется объект, созданный с помощью объектного литерала.
Или мы создали объект, воспользовавшись конструктором Object .
В любом из этих случаев прототипом объекта car будет Object.prototype .
Если создать массив, который тоже является объектом, его прототипом будет объект Array.prototype .
Проверить это можно следующим образом.
Здесь мы пользовались свойством __proto__ , оно не обязательно должно быть доступно разработчику, но обычно обращаться к нему можно. Надо отметить, что более надёжным способом получить прототип объекта является использование метода getPrototypeOf() глобального объекта Object .
Все свойства и методы прототипа доступны объекту, имеющему этот прототип. Вот, например, как выглядит их список для массива.

Подсказка по массиву
Базовым прототипом для всех объектов является Object.prototype .
У Object.prototype прототипа нет.
То, что мы видели выше, является примером цепочки прототипов.
При попытке обращения к свойству или методу объекта, если такого свойства или метода у самого объекта нет, их поиск выполняется в его прототипе, потом — в прототипе прототипа, и так — до тех пор, пока искомое будет найдено, или до тех пор, пока цепочка прототипов не кончится.
Помимо создания объектов с использованием оператора new и применения объектных литералов или литералов массивов, создать экземпляр объекта можно с помощью метода Object.create() . Первый аргумент, передаваемый этому методу, представляет собой объект, который станет прототипом создаваемого с его помощью объекта.
Проверить, входит ли некий объект в цепочку прототипов другого объекта, можно с использованием метода isPrototypeOf() .
Функции-конструкторы
Выше мы создавали новые объекты, пользуясь уже имеющимися в языке функциями-конструкторами (при их вызове используется ключевое слово new ). Такие функции можно создавать и самостоятельно. Рассмотрим пример.
Здесь мы создаём функцию-конструктор. При её вызове создаётся новый объект, на который указывает ключевое слово this в теле конструктора. Мы добавляем в этот объект свойство name и записываем в него то, что передано конструктору. Этот объект возвращается из конструктора автоматически. С помощью функции-конструктора можно создать множество объектов, свойства name которых будут содержать то, что передано при их создании конструктору.
После создания конструктора мы добавляем в его прототип функцию, которая будет выводить в консоль значение свойства name объекта, созданного с помощью этой функции. Все объекты, созданные с помощью этого конструктора, будут иметь один и тот же прототип, а значит и пользоваться одной и той же функцией hello() . Это несложно проверить, создав ещё один объект типа Person и сравнив его функцию hello() с функцией уже имеющегося в примере объекта (имя функции в таком случае записывают без скобок).
▍Классы
В стандарте ES6 в JavaScript пришло такое понятие как «класс».
До этого в JavaScript можно было пользоваться лишь вышеописанным механизмом прототипного наследования. Этот механизм непривычно выглядел для программистов, пришедших в JS из других языков. Поэтому в языке и появились классы, которые, по сути, являются «синтаксическим сахаром» для прототипного механизма наследования. То есть, и объекты, созданные традиционным способом, и объекты, созданные с использованием классов, имеют прототипы.
Объявление класса
Вот как выглядит объявление класса.
У класса есть идентификатор, который можно использовать для создания новых объектов с применением конструкции new ClassIdentifier() .
При создании нового объекта вызывается метод constructor , ему передаются параметры.
В классе можно объявлять методы. В нашем случае hello() — это метод, который могут вызывать все объекты, созданные на основе класса. Вот как выглядит создание нового объекта с использованием класса Person .
Наследование, основанное на классах
Классы могут расширять другие классы. Объекты, созданные на основе таких классов, будут наследовать и методы исходного класса, и методы, заданные в расширенном классе.
Если класс, расширяющий другой класс (наследник этого класса) имеет метод, имя которого совпадает с тем, который есть у класса-родителя, этот метод имеет преимущество перед исходным.
При вызове метода hello() в вышеприведённом примере будет возвращена строка Hello, I am Flavio. I am a programmer .
В классах не предусмотрено наличие переменных (свойств), свойства создаваемых с помощью классов объектов нужно настраивать в конструкторе.
Внутри класса можно обращаться к родительскому классу с использованием ключевого слова super .
Статические методы
Методы, описываемые в классе, можно вызывать, обращаясь к объектам, созданным на основе этого класса, но не к самому классу. Статические ( static ) методы можно вызывать, обращаясь непосредственно к классу.
Приватные методы
В JavaScript нет встроенного механизма, который позволяет объявлять приватные (частные, закрытые) методы. Это ограничение можно обойти, например, с использованием замыканий.
Геттеры и сеттеры
В классе можно описывать методы, предваряя их ключевыми словами get или set . Это позволяет создавать так называемые геттеры и сеттеры — функции, которые используются для управления доступом к свойствам объектов, созданных на основе класса. Геттер вызывается при попытке чтения значения псевдо-свойства, а сеттер — при попытке записи в него нового значения.
Итоги
В этом материале мы поговорили о переменных, о типах данных, о выражениях и о работе с объектами в JavaScript. Темой нашего следующего материала будут функции.
Уважаемые читатели! Если вы уже давно пишете на JS, просим рассказать о том, как вы относитесь к появлению в языке ключевого слова class.
Памятка по современному 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 такое же, как и во внешней области видимости. В принципе, со стрелочными функциями вам больше не нужно прибегать к хаку 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, аргументам функции можно присваивать значения по умолчанию, используя следующий синтаксис:
Значения по умолчанию применяются только в двух случаях:
Другими словами, если передать в функцию параметр null , то параметр по умолчанию не применится.
Примечание: Присваивать значение по умолчанию можно в том числе и при работе с деструктурированными параметрами (см. пример в следующем понятии).
Дополнительные материалы
Деструктуризация объектов и массивов
Деструктуризация — это удобный способ создания новых переменных путем извлечения значений из объектов или массивов.
На практике деструктуризацию можно использовать, чтобы присваивать переменным разбитые на части параметры функции или this.props в React-проектах.
Объяснение с помощью примера кода
Давайте использовать во всех примерах следующий объект:
С деструктуризацией всё поместится в одну строку:
Примечание: В const < age >= person; скобки после ключевого слова const используются не для обозначения объекта или блока. Это синтаксис деструктуризации.
Деструктуризация часто используется для разбиения параметров функции на части.
Если деструктурировать параметр person , то функция получится куда более лаконичной:
Ещё удобнее использовать деструктуризацию со стрелочными функциями:
Давайте рассмотрим следующий массив:
С использованием деструктуризации:
Полезные ресурсы
Методы массивов — map / filter / reduce
map , filter и 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 применяется к массиву и в качестве первого параметра принимает функцию.
На этот раз, впрочем, кое-что изменилось:
Первый параметр — это функция, которая будет вызываться на каждом шаге цикла.
Второй параметр — это значение аккумулирующей переменной ( 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 используется для вызова функций родителя объекта, включая его конструктор.
Пример кода
Примечание: Если бы мы попытались использовать 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 (истина), кроме:
Вот примеры булева контекста:
-
значение условия if .
Значение myVar может быть любым объектом первого класса (переменная, функция, логическое значение), но оно будет преобразовано в логическое значение, поскольку вычисляется в булевом контексте.
Этот оператор возвращает значение «ложь», если его единственный операнд может быть преобразован к значению «истина»; иначе он возвращает значение «истина».
Значение myVar вычисляется в булевом контексте.
Будьте внимательны при сравнении двух значений. Значения объектов (которые должны быть приведены к истине), не приводятся к булеву типу, а приводятся к примитивному типу в соответствии со спецификацией. Внутри, когда объект сравнивается с булевым значением, например, [] == true , выполняется [].toString() == true , происходит следующее:
Дополнительные материалы
Анаморфизмы и катаморфизмы
Анаморфизмы
Анаморфизмы — это фунции, которые отображают некоторый объект на более сложную структуру, содержащую тип объекта. Это процесс разворачивания простой структуры в более сложную.
Рассмотрим разворачивание целого числа в список целых чисел. Целое число — наш изначальный объект, а список целых чисел — более сложная структура.
Пример кода
Катаморфизмы
Катаморфизмы противоположны анаморфизмам: они берут объекты более сложной структуры и складывают их в более простые структуры.
Рассмотрим следующий пример функции product , которая принимает список целых чисел и возвращает простое целое число.
Пример кода
Дополнительные материалы
Генераторы
Другой способ написания функции downToOne — использование генератора. Чтобы создать объект типа Generator , нужно использовать объявление function * . Генераторы — это функции, выполнение которых может быть прервано, а затем продолжено с тем же контекстом (привязками переменных), сохраняющимся при всех вызовах.
Например, функция downToOne может быть переписана следующим образом:
Генераторы возвращают итерируемый объект. Когда вызывается метод next() итератор, она выполняется до первого выражения yield , которое указывает значение, которое должно быть возвращено из итератора или с помощью yield* , которое дегегирует выполнение другому генератору. Когда в генераторе вызывается выражение return , он будет помечать генератор как выполненный и возвращать значение из выражения return . Дальнейшие вызовы next() не будут возвращать никаких новых значений.
Пример кода
Выражение yield* позволяет генератору вызывать другую функцию-генератор во время итерации.