Литерал объекта JavaScript описание новых функций и возможностей в ES6


Содержание материала:

Литерал объекта JavaScript: описание новых функций и возможностей в ES6

Возможно, вам уже знаком термин — объект (англ. object ).

Объекты похожи на массивы , но вместо использования индексов для доступа и изменения данных, в объектах доступ к данным осуществляется при помощи свойств ( англ. properties ).

Один из способов создать объект — это воспользоваться литералом объекта. Литерал объекта — это заключённый в фигурные скобки список из нуля или более свойств (пар имя: значение), разделённых запятыми.

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

Вот пример литерала объекта:

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

Задание

Создайте объект myDog представляющий собаку, который содержит свойства «name» (имя), «legs» (кол-во ног), «tails» (кол-во хвостов) и «friends» (друзья).

Вы можете назначить свойствам объекта myDog любые значение, но тип данных значений должен быть: «name» — строка, «legs» и «tails» — числа, «friends» — массив.

Классы JavaScript в ES6. Часть 2

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

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

let app = new class
constructor(name)
this.name = name;
>

app.start(); // Запуск приложения TodoList…

В этом примере мы создаем анонимный класс и выполняем его немедленно.

Геттеры и сеттеры

Чтобы создать getter и setter методы , нужно использовать ключевые слова get и set, за которыми следуют пробел и идентификатор.

constructor(firstName, lastName) <
this.firstName = firstName;
this.lastName = lastName;
>

get fullName() <
return this.firstName + ‘ ‘ + this.lastName;
>

set fullName(str) <
let names = str.split(‘ ‘);
if (names.length === 2) <
this.firstName = names[0];
this.lastName = names[1];
> else <
throw ‘Неправильный формат имени’;
>

let mary = new Person(‘Мария’, ‘Дорош’);
console.log(mary.fullName); // Мария Дорош

// устанавливаем новое имя
mary.fullName = ‘Мэри Уильям’;
console.log(mary.fullName); // Мэри Уильям

Вызов метода fullName возвращает полное имя объекта person, объединяя имя и фамилию через пробел.
Метод setName принимает строку в качестве аргумента. Он разбивает строку на части и присваивает свойства firstName и lastName соответствующим свойствам класса. Если входной аргумент в неправильном формате, то есть имя, пробел и фамилия не присутствуют во входной строке, данный метод вызывает ошибку.

Вычисляемые имена свойств

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

let name = ‘fullName’;

class Person <
constructor(firstName, lastName) <
this.firstName = firstName;
this.lastName = lastName;
>
get[name] <
return this.firstName + ‘ ‘ + this.lastName;
>
set[name](str) <
//.
>
>

var john = new Person(‘John’, ‘Doe’);
console.log(john.fullName); // John Doe

Статические методы

До ES6, чтобы создать статический метод, необходимо было добавить метод непосредственно к функции-конструктору. Например, в примере далее добавляется статический метод к типу Animal, определенному в предыдущем примере.

Animal.make = function(type) <
return new Animal(type);
>

var dog = Animal.make(‘Собака’);
dog.identify(); // Собака

Метод make() считается статическим методом, поскольку он не зависит от какого-либо экземпляра класса Animal. ES6 упростил задачу создания статических, используя ключевое слово static для метода , как показано в следующем примере.

class Animal <
constructor(type) <
this.type = type;
>
identify() <
console.log(this.type);
>
static create(type) <
return new Animal(type);
>
>

var mouse = Animal.create(‘Мышь’);
mouse.identify(); // Мышь

Обратите внимание, что попытка получить доступ к статическому методу из экземпляра класса приводит к ошибке.

mouse.create(‘Обезьянка’); // Ошибка TypeError: mouse.create не является функцией

Таким образом, теперь вы знаете, как использовать классы в JavaScript ES6 и как применять их для разработки пользовательских типов в приложениях.

Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!

Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.

Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления

Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

Порекомендуйте эту статью друзьям:

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

Она выглядит вот так:

  • BB-код ссылки для форумов (например, можете поставить её в подписи):
  • Комментарии ( 1 ):

    Для добавления комментариев надо войти в систему.
    Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.

    Copyright © 2010-2020 Русаков Михаил Юрьевич. Все права защищены.

    Объекты

    Как мы знаем из главы Типы данных, в JavaScript существует семь типов данных. Шесть из них называются «примитивными», так как содержат только одно значение (будь то строка, число или что-то другое).

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

    Объект может быть создан с помощью фигурных скобок <…>с необязательным списком свойств. Свойство – это пара «ключ: значение», где ключ – это строка (также называемая «именем свойства»), а значение может быть чем угодно.

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

    Пустой объект («пустой ящик») можно создать, используя один из двух вариантов синтаксиса:

    Обычно используют вариант с фигурными скобками <. >. Такое объявление называют литералом объекта или литеральной нотацией.

    Литералы и свойства

    При использовании литерального синтаксиса <. >мы сразу можем поместить в объект несколько свойств в виде пар «ключ: значение»:

    Свойства объекта также иногда называют полями объекта.

    У каждого свойства есть ключ (также называемый «имя» или «идентификатор»). После имени свойства следует двоеточие «:» , и затем указывается значение свойства. Если в объекте несколько свойств, то они перечисляются через запятую.

    В объекте user сейчас находятся два свойства:

    1. Первое свойство с именем «name» и значением «John» .
    2. Второе свойство с именем «age» и значением 30 .

    Можно сказать, что наш объект user – это ящик с двумя папками, подписанными «name» и «age».

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

    Для обращения к свойствам используется запись «через точку»:

    Значение может быть любого типа. Давайте добавим свойство с логическим значением:

    Для удаления свойства мы можем использовать оператор delete :

    Имя свойства может состоять из нескольких слов, но тогда оно должно быть заключено в кавычки:

    Последнее свойство объекта может заканчиваться запятой:

    Это называется «висячая запятая». Такой подход упрощает добавление, удаление и перемещение свойств, так как все строки объекта становятся одинаковыми.

    Квадратные скобки

    Для свойств, имена которых состоят из нескольких слов, доступ к значению «через точку» не работает:

    Так происходит, потому что точка требует, чтобы ключ был именован по правилам именования переменных. То есть не имел пробелов, не начинался с цифры и не содержал специальные символы, кроме $ и _ .

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

    Сейчас всё в порядке.

    Обратите внимание, что строка в квадратных скобках закавычена (подойдёт любой тип кавычек).

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

    Здесь переменная key может быть вычислена во время выполнения кода или зависеть от пользовательского ввода. После этого мы используем её для доступа к свойству. Это даёт нам большую гибкость.

    Запись «через точку» такого не позволяет:

    Вычисляемые свойства

    Мы можем использовать квадратные скобки в литеральной нотации для создания вычисляемого свойства.

    Смысл вычисляемого свойства прост: запись [fruit] означает, что имя свойства необходимо взять из переменной fruit .

    И если посетитель введёт слово «apple» , то в объекте bag теперь будет лежать свойство .

    По сути, пример выше работает так же, как и следующий пример:

    …Но первый пример выглядит лаконичнее.

    Мы можем использовать и более сложные выражения в квадратных скобках:

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

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

    Имя переменной не может совпадать с зарезервированными словами, такими как «for», «let», «return» и т.д.

    Но для свойств объекта такого ограничения нет:

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

    Как мы видим, присвоение примитивного значения 5 игнорируется.

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

    Посетитель может указать __proto__ в качестве ключа, и логика присваивания будет нарушена (как показано выше).

    Есть способ заставить объекты обрабатывать __proto__ как обычное свойство. Мы поговорим о нём позже, а пока нам нужно узнать больше об объектах.

    Также существует другая структура данных Map, которая поддерживает произвольные ключи. Мы изучим её в главе Map и Set.

    Свойство из переменной

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

    В примере выше название свойств name и age совпадают с названиями переменных, которые мы подставляем в качестве значений этих свойств. Такой подход настолько распространён, что существуют специальные короткие свойства для упрощения этой записи.

    Вместо name:name мы можем написать просто name :

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

    Проверка существования свойства

    Особенность объектов в том, что можно получить доступ к любому свойству. Даже если свойства не существует – ошибки не будет! При обращении к свойству, которого нет, возвращается undefined . Это позволяет просто проверить существование свойства – сравнением его с undefined :

    Также существует специальный оператор «in» для проверки существования свойства в объекте.

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

    Если мы опускаем кавычки, это значит, что мы указываем переменную, в которой находится имя свойства. Например:

    Обычно строгого сравнения «=== undefined» достаточно для проверки наличия свойства. Но есть особый случай, когда оно не подходит, и нужно использовать «in» .

    Это когда свойство существует, но содержит значение undefined :

    В примере выше свойство obj.test технически существует в объекте. Оператор in сработал правильно.

    Подобные ситуации случаются очень редко, так как undefined обычно явно не присваивается. Для «неизвестных» или «пустых» свойств мы используем значение null . Таким образом, оператор in является экзотическим гостем в коде.

    Цикл «for…in»

    Для перебора всех свойств объекта используется цикл for..in . Этот цикл отличается от изученного ранее цикла for(;;) .

    К примеру, давайте выведем все свойства объекта user :

    Обратите внимание, что все конструкции «for» позволяют нам объявлять переменную внутри цикла, как, например, let key здесь.

    Кроме того, мы могли бы использовать другое имя переменной. Например, часто используется вариант «for (let prop in obj)» .

    Упорядочение свойств объекта

    Упорядочены ли свойства объекта? Другими словами, если мы будем в цикле перебирать все свойства объекта, получим ли мы их в том же порядке, в котором мы их добавляли? Можем ли мы на это рассчитывать?

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

    В качестве примера рассмотрим объект с телефонными кодами:

    Если мы делаем сайт для немецкой аудитории, то, вероятно, мы хотим, чтобы код 49 был первым.

    Но если мы запустим код, мы увидим совершенно другую картину:

    • США (1) идёт первым
    • затем Швейцария (41) и так далее.

    Телефонные коды идут в порядке возрастания, потому что они являются целыми числами: 1, 41, 44, 49 .

    Термин «целочисленное свойство» означает строку, которая может быть преобразована в целое число и обратно без изменений.

    То есть, «49» – это целочисленное имя свойства, потому что если его преобразовать в целое число, а затем обратно в строку, то оно не изменится. А вот свойства «+49» или «1.2» таковыми не являются:

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

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

    Теперь код работает так, как мы задумывали.

    Копирование по ссылке

    Одним из фундаментальных отличий объектов от примитивных типов данных является то, что они хранятся и копируются «по ссылке».

    Примитивные типы: строки, числа, логические значения – присваиваются и копируются «по значению».

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

    Объекты ведут себя иначе.

    Переменная хранит не сам объект, а его «адрес в памяти», другими словами «ссылку» на него.

    Сам объект хранится где-то в памяти. А в переменной user лежит «ссылка» на эту область памяти.

    Когда переменная объекта копируется – копируется ссылка, сам же объект не дублируется.

    Если мы представляем объект как ящик, то переменная – это ключ к нему. Копирование переменной дублирует ключ, но не сам ящик.

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

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

    Приведённый выше пример демонстрирует, что объект только один. Как если бы у нас был один ящик с двумя ключами и мы использовали один из них ( admin ), чтобы войти в него и что-то изменить, а затем, открыв ящик другим ключом ( user ), мы бы увидели эти изменения.

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

    Операторы равенства == и строгого равенства === для объектов работают одинаково.

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

    Например, две переменные ссылаются на один и тот же объект, они равны:

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

    Для сравнений типа obj1 > obj2 или для сравнения с примитивом obj == 5 объекты преобразуются в примитивы.

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

    Объекты-константы

    Объект, объявленный через const , может быть изменён.

    Может показаться, что строка (*) должна вызвать ошибку, но нет, здесь всё в порядке. Дело в том, что объявление const защищает от изменений только само значение user . А в нашем случае значение user – это ссылка на объект, и это значение мы не меняем. В строке (*) мы действуем внутри объекта, мы не переназначаем user .

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

    …Но что делать, если мы хотим сделать константами свойства объекта? Как сделать так, чтобы попытка изменить user.age = 25 выдавала ошибку? Это тоже возможно. Мы рассмотрим эту тему в главе Флаги и дескрипторы свойств.

    Клонирование и объединение объектов, Object.assign

    Как мы узнали ранее, при копировании переменной объекта создаётся ещё одна ссылка на тот же самый объект.

    Но что, если нам всё же нужно дублировать объект? Создать независимую копию, клон?

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

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

    Кроме того, для этих целей мы можем использовать метод Object.assign.

    • Аргументы dest , и src1, . srcN (может быть столько, сколько нужно) являются объектами.
    • Метод копирует свойства всех объектов src1, . srcN в объект dest . То есть, свойства всех перечисленных объектов, начиная со второго, копируются в первый объект. После копирования метод возвращает объект dest .

    Например, объединим несколько объектов в один:

    Если принимающий объект ( user ) уже имеет свойство с таким именем, оно будет перезаписано:

    Мы также можем использовать Object.assign для простого клонирования:

    Все свойства объекта user будут скопированы в пустой объект, и ссылка на этот объект будет в переменной clone . На самом деле, такое клонирование работает так же, как и через цикл, но короче.

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

    Например, есть объект:

    Теперь при клонировании недостаточно просто скопировать clone.sizes = user.sizes , поскольку user.sizes – это объект, он будет скопирован по ссылке. А значит объекты clone и user в своих свойствах sizes будут ссылаться на один и тот же объект:

    Чтобы исправить это, мы должны в цикле клонирования делать проверку, не является ли значение user[key] объектом, и если это так – копируем и его структуру тоже. Это называется «глубокое клонирование».

    Существует стандартный алгоритм глубокого клонирования, Structured cloning algorithm. Он решает описанную выше задачу, а также более сложные задачи. Чтобы не изобретать велосипед, мы можем использовать реализацию этого алгоритма из JavaScript-библиотеки lodash, метод _.cloneDeep(obj).

    Топ-пост этого месяца:  Секреты эффективных объявлений в контекстной рекламе

    Итого

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

    Они хранят свойства (пары ключ-значение), где:

    • Ключи свойств должны быть строками или символами (обычно строками).
    • Значения могут быть любого типа.

    Чтобы получить доступ к свойству, мы можем использовать:

    • Запись через точку: obj.property .
    • Квадратные скобки obj[«property»] . Квадратные скобки позволяют взять ключ из переменной, например, obj[varWithKey] .
    • Удаление свойства: delete obj.prop .
    • Проверка существования свойства: «key» in obj .
    • Перебор свойств объекта: цикл for for (let key in obj) .

    Объекты присваиваются и копируются по ссылке. Другими словами, переменная хранит не «значение объекта», а «ссылку» (адрес в памяти) на это значение. Поэтому копирование такой переменной или передача её в качестве аргумента функции приводит к копированию этой ссылки, а не самого объекта. Все операции с использованием скопированных ссылок (например, добавление или удаление свойств) выполняются с одним и тем же объектом.

    Чтобы сделать «настоящую копию» (клон), мы можем использовать Object.assign или _.cloneDeep(obj).

    То, что мы изучали в этой главе, называется «простым объектом» («plain object») или просто Object .

    В JavaScript есть много других типов объектов:

    • Array для хранения упорядоченных коллекций данных,
    • Date для хранения информации о дате и времени,
    • Error для хранения информации об ошибке.
    • … и так далее.

    У них есть свои особенности, которые мы изучим позже. Иногда люди говорят что-то вроде «тип данных Array» или «тип данных Date», но формально они не являются отдельными типами, а относятся к типу данных Object . Они лишь расширяют его различными способами.

    Объекты в JavaScript очень мощные. Здесь мы только немного углубились в действительно огромную тему. Мы будем плотно работать с объектами и узнаем о них больше в следующих частях учебника.

    Задачи

    Привет, object

    Напишите код, выполнив задание из каждого пункта отдельной строкой:

    1. Создайте пустой объект user .
    2. Добавьте свойство name со значением John .
    3. Добавьте свойство surname со значением Smith .
    4. Измените значение свойства name на Pete .
    5. Удалите свойство name из объекта.

    решение

    [Перевод] Новшества объектных литералов в JavaScript ES6

    Материал, перевод которого мы представляем вашему вниманию, посвящён исследованию особенностей объектных литералов в JavaScript, в частности — новшеств, которые появились в свежих версиях стандарта ECMAScript.

    Стандарт ES2015 (ES6) упрощает работу с объектами при создании приложений для современных браузеров (кроме IE) и для платформы Node.js. JavaScript обладает мощной и удобной возможностью создания объектов с использованием объектных литералов.

    Основы

    Создание объектов в некоторых языках может требовать больших затрат ресурсов, под которыми мы имеем в виду и рабочее время программиста, и вычислительные ресурсы систем. В частности, речь идёт о том, что, прежде чем создавать объекты, необходимо описывать классы (скажем, с помощью ключевого слова class ). В JavaScript объекты можно создавать очень быстро и просто, без необходимости выполнения каких-либо предварительных действий. Рассмотрим пример:

    // ES5
    var myObject =
    >; myObject.output(); // hello world

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

    Инициализация объектов из переменных

    Свойства объектов часто создают из переменных, назначая им те же имена, которые уже назначены этим переменным. Например:

    // ES5
    var a = 1, b = 2, c = 3; obj = < a: a, b: b, c: c >; // obj.a = 1, obj.b = 2, obj.c = 3

    В ES6 больше не нужно повторять имена переменных:

    // ES6
    const a = 1, b = 2, c = 3; obj = < a, b, c >; // obj.a = 1, obj.b = 2, obj.c = 3

    Этот приём может оказаться полезным для возвращаемых объектов при использовании паттерна Revealing Module, который позволяет создавать пространства имён для различных фрагментов кода для того, чтобы избежать конфликтов имён. Например:

    // ES6
    const lib = (() => < function sum(a, b) < return a + b; >function mult(a, b) < return a * b; >return < sum, mult >; >()); console.log( lib.sum(2, 3) ); // 5
    console.log( lib.mult(2, 3) ); // 6

    Возможно, вы видели как этот приём используется в ES6-модулях:

    Сокращённый синтаксис объявления методов объектов

    При объявлении методов объектов в ES5 необходимо использовать ключевое слово function :

    // ES5
    var lib = < sum: function(a, b) < return a + b; >, mult: function(a, b) < return a * b; >
    >; console.log( lib.sum(2, 3) ); // 5
    console.log( lib.mult(2, 3) ); // 6

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

    // ES6
    const lib = < sum(a, b) < return a + b; >, mult(a, b) < return a * b; >
    >; console.log( lib.sum(2, 3) ); // 5
    console.log( lib.mult(2, 3) ); // 6

    Надо отметить, что здесь нельзя использовать стрелочные функции ES6 ( => ), так как у методов должны быть имена. Однако стрелочные функции можно использовать если явно назначать имена методам (как в ES5). Например:

    // ES6
    const lib = < sum: (a, b) =>a + b, mult: (a, b) => a * b
    >; console.log( lib.sum(2, 3) ); // 5
    console.log( lib.mult(2, 3) ); // 6

    Динамические ключи

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

    // ES5
    var key1 = ‘one’, obj = < two: 2, three: 3 >; obj[key1] = 1; // obj.one = 1, obj.two = 2, obj.three = 3

    В ES6 ключи можно назначать динамически, помещая выражение, определяющее имя, в квадратные скобки ( [] ). Например:

    // ES6
    const key1 = ‘one’, obj = < [key1]: 1, two: 2, three: 3 >; // obj.one = 1, obj.two = 2, obj.three = 3

    Для создания ключа можно использовать любое выражение:

    // ES6
    const i = 1, obj = < ['i' + i]: i >; console.log(obj.i1); // 1

    Динамические ключи можно использовать и для методов, и для свойств:

    // ES6
    const i = 2, obj = < ['mult' + i]: x =>x * i >; console.log( obj.mult2(5) ); // 10

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

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

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

    // ES5
    var myObject = < one: 'a', two: 'b', three: 'c'
    >; var one = myObject.one, // ‘a’ two = myObject.two, // ‘b’ three = myObject.three; // ‘c’

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

    Переменные, в которые попадают значения свойств объекта, могут, на самом деле, иметь любые имена, но в том случае, если они отличаются от имён свойств, необходимо пользоваться конструкцией < propertyName: newVariable >:

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

    Поначалу всё это может показаться сложным, однако, с этим не так уж и тяжело разобраться, главное — помнить следующее:

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

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

    Эта конструкция нормально воспринимается системой при объявлении переменных:

    const < a, b, c >= myObject; // правильно

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

    let a, b, c;
    ( < a, b, c >= myObject); // правильно

    В результате, занимаясь деструктурированием, следует внимательно относиться к коду и не смешивать объявленные и необъявленные переменные.

    Деструктурирование — это приём, который может пригодиться во многих ситуациях.

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

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

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

    // ES5, назначение значений по умолчанию
    function prettyPrint(param) < param = param || <>; var pubTitle = param.title || ‘No title’, pubName = (param.publisher && param.publisher.name) || ‘No publisher’; return pubTitle + ‘, ‘ + pubName; >

    В ES6 любым параметрам можно назначать значения по умолчанию:

    // ES6 — значения параметров по умолчанию
    function prettyPrint(param = <>)

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

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

    Разбор объектов, возвращаемых функциями

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

    // ES5
    var obj = getObject(), one = obj.one, two = obj.two, three = obj.three;

    Деструктурирование упрощает этот процесс. Теперь всё это можно сделать без необходимости сохранения объекта в отдельной переменной и последующего его разбора:

    Возможно, вы видели нечто подобное в программах для Node.js. Например, если вам нужны только методы readFile() и writeFile() модуля fs , получить ссылки на них можно так:

    Синтаксис оставшихся параметров и оператор расширения ES2020 (ES9)

    =В ES2015 синтаксис оставшихся параметров и оператор расширения (и тот и другой выглядят как три точки, … ) применялись лишь при работе с массивами. В ES2020 похожий функционал можно использовать и для работы с объектами:

    const myObject = < a: 1, b: 2, c: 3
    >; const < a, . x >= myObject;
    // a = 1
    // x =

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

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

    Оператор расширения можно использовать внутри объектов:

    Оператор расширения допустимо применять для клонирования объектов ( obj2 = < . obj1 >; ), однако тут надо учитывать то, что при таком подходе выполняется мелкая копия объекта. Если свойствами объектов являются другие объекты, клон объекта будет ссылаться на те же самые вложенные объекты.

    В настоящий момент ими, без дополнительных усилий, можно пользоваться в браузерах Chrome и Firefox, и при разработке для платформы Node.js версии 8. Синтаксис оставшихся параметров и оператор расширения пока пользуются не слишком широкой поддержкой. 6 и выше.

    Итоги

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

    Уважаемые читатели! Какими способами создания JS-объектов вы пользуетесь чаще всего?

    Frontender Magazine

    ES6 в деталях — это цикл статей о новых возможностях языка программирования JavaScript, появившихся в 6 редакции стандарта ECMAScript, кратко — ES6.

    Стрелки были частью JavaScript с самого начала. Первые учебники по JavaScript советовали оборачивать встроенные скрипты в комментарии HTML. Это не позволяло тем браузерам, что не поддерживали JS, ошибочно отображать код JS как текст. В то время вы бы писали примерно так:

    Старые браузеры видели два неподдерживаемых тега и комментарий, и только новые браузеры видели в этом JS.

    Чтобы поддерживать этот костыль, движок JavaScript в браузере рассматривает символы как начало однострочного комментария. Кроме шуток. Это действительно всё время было частью языка и работает по сей день, не только сразу после открывающего тега , но и вообще в любом месте JS-кода. Даже в Node.js работает.

    Последовательность символов в виде стрелки также обозначает однострочный комментарий. Интересно, что в HTML комментарием считаются символы перед , а в JS комментарий — это всё, что после и до конца строки.

    А вот что ещё интересней. Эта стрелка обозначает комментарий только если находится в начале строки. Потому, что в других контекстах в JS — оператор «стремится к»!

    Этот код действительно работает. Цикл выполняется, пока n не достигнет 0 . Это тоже не новая возможность ES6, а комбинация старых в новом контексте и небольшой фокус с записью операторов. Сможете разобраться, как это работает? Как обычно, разгадку можно найти на Stack Overflow.

    Разумеется, есть ещё оператор «меньше или равно», . Возможно, вы сможете, как в игре Поиск Предметов, отыскать в исходном коде программ написанных на JavaScript и другие виды стрелок, но давайте на этом остановимся, как бы вы не искали, одной стрелки всё равно не хватает.

    однострочный комментарий
    оператор «стремится к»
    меньше или равно
    => .

    Что за => ? Сейчас разберемся.

    Но сначала немного о функциях.

    Функции-выражения повсюду

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

    Например, предположим, вы хотите сказать браузеру, что ему следует делать, если пользователь нажмёт определённую кнопку. Вы начинаете печатать:

    Метод .click() jQuery принимает один аргумент — функцию. Без проблем. Вы можете впечатать функцию прямо туда:

    Мы уже привыкли писать так, это для нас уже вполне естественно. И странно вспоминать, что до того как, благодаря JavaScript, такой подход к программированию стал популярен, во многих языках не было такой возможности. Само собой, в Lisp были функции-выражения, они же лямбда-функции, ещё с 1958. Но C++, Python, C# и Java просуществовали годы без них.

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

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

    Новая стрела в ваш колчан

    В ES6 появился новый синтаксис функций.

    Если вам нужна простая функция с одним аргументом, то синтаксис новых, стрелочных функций — это просто Идентификатор => Выражение . Не нужно печатать ни function , ни return , ни круглых скобок с фигурными и точкой с запятой.

    (Лично я очень благодарен за этот синтаксис. Для меня очень важно, что печатать function больше не надо, потому что у меня постоянно вместо этого получается functoin , и мне приходится возвращаться и исправлять опечатку.)

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

    Мне кажется, выглядит очень неплохо.

    Стрелочные функции точно так же великолепно работают с функциональными утилитами из библиотек наподобие Underscore.js и Immutable. В сущности, все примеры кода в документации Immutable написаны на ES6, так что многие из них уже используют стрелочные функции.

    А что насчёт не столь функциональных случаев? Стрелочные функции могут содержать блок инструкций вместо одиночного выражения. Вернёмся к более раннему примеру:

    Вот так это будет выглядеть в ES6:

    Небольшое улучшение. Эффект при использовании промисов может быть более заметным из-за нагроможения строчек >).then(function (result) < .

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

    Есть ещё один нюанс, когда стрелочные функции используются для создания объектов. Всегда оборачивайте объект в скобки:

    Увы, пустой объект <> и пустой блок <> выглядят абсолютно одинаково. Правила ES6 гласят: < сразу после стрелки всегда трактуется как начало блока и никогда не считается началом объекта. Поэтому код puppy =><> молча интерпретируется как стрелочная функция, которая ничего не делает и возвращает undefined .

    Ещё больше сбивает с толку то, что литерал вроде выглядит в точности как блок, содержащий инструкцию с меткой; по крайней мере, он так выглядит для движка JavaScript. К счастью, < — это единственный неоднозначный символ, так что единственный приём, который вам следует запомнить,— это оборачивание литералов объектов в скобки.

    Что такое this ?

    Есть одно хитрое отличие в поведении обычных функций- function и стрелочных функций. У стрелочных функций нет собственного значения this . Внутри стрелочной функции this всегда наследуется из окружающего лексического окружения.

    Перед тем как мы постараемся выяснить, что это значит на практике, давайте ненадолго обратимся к основам.

    Как в JavaScript работает this ? Откуда берётся это значение? На этот вопрос нет короткого ответа. Если для вашего мозга это просто — это лишь из-за того, что вы с этим долго работали!

    Одна из причин, почему этот вопрос всплывает так часто — это то, что функции- function получают значение this автоматически, неважно, нужно оно им или нет. Вы когда-нибудь применяли такой приём?

    Здесь вам бы хотелось написать внутреннюю функцию просто как this.add(piece) . К несчастью, внутренняя функция не наследует this внешней. Во внутренней функции this будет window или undefined . Временная переменная self нужна, чтобы протащить внешнее значение this во внутреннюю функцию. (Ещё один способ — использовать .bind(this) на внутренней функции. И оба эти способа особым изяществом не отличаются.)

    В ES6 трюки с this по большей части не нужны, если вы придерживаетесь этих правил:

    Использовать не-стрелочные функции для методов, которые будут вызываться с использованием синтаксиса объект.метод() . Эти функции получат вменяемый this от вызывающего кода.

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

    Обратите внимание, в этой версии на ES6 метод addAll получает this от вызывающего кода. Внутренняя функция — стрелочная, так что она наследует this из лексического окружения.

    Что приятно, ES6 также предоставляет более краткий способ записи методов в литералах объектов! Так что код выше можно сделать ещё проще:

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

    Есть ещё одна небольшая разница между стрелочными и не-стрелочными функциями: стрелочные функции не получают собственного объекта arguments . Разумеется, в ES6 вы и так скорее предпочтёте остаточные параметры или значения по умолчанию.

    Пронзаем стрелами тёмное сердце информатики

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

    В 1936 Алонзо Чёрч и Алан Тьюринг независимо друг от друга разработали мощные математические вычислительные модели. Тьюринг назвал свою модель а-машины, но остальные немедленно окрестили их машинами Тьюринга. Чёрч, напротив, писал о функциях. Его модель называлась λ-исчисление. (λ — это строчная греческая буква лямбда.) Его работа послужила причиной тому, что в Lisp для обозначений функций использовалось слово LAMBDA , и поэтому наши дни мы называем функции-выражения лямбдами.

    Но что такое λ-исчисление? И что имеется в виду под вычислительной моделью?

    Непросто объяснить это в двух словах, но я попробую: λ-исчисление — это один из первых языков программирования. Оно не было спроектировано как язык программирования (в конце концов, до компьютеров, хранящих программу в памяти, было на тот момент лет десять или двадцать), а скорее, это было бесцеремонно простой, обнажённой, чисто математической идеей языка, который мог бы выразить любой вид вычислений, какой только захочется. Чёрчу нужна была эта модель, чтобы доказать свои мысли о вычислении в целом.

    И он обнаружил, что в его модели нужно только одно — функции.

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

    Например, вот такую «программу» могут написать математики в λ-нотации Чёрча:

    Эквивалентная функция JavaScript выглядит так:

    То есть JavaScript содержит работающую реализацию λ-исчисления. λ-исчисление есть в JavaScript.

    Истории о том, как Алонзо Чёрч и поздние исследователи развивали λ-исчисление, и о том, как оно незаметно проникло в практически все заметные языки программирования, находятся уже за пределами тематики этой статьи. Но если вы заинтересовались основателями информатики или хотели бы взглянуть на то, как в языке, в котором нет ничего, кроме функций, можно делать вещи вроде циклов и рекурсии, то вы могли бы в какой-нибудь пасмурный день почитать про нотацию Чёрча и комбинаторы неподвижной точки и поиграться с ними в консоли Firefox или Scratchpad. Со стрелочными функциями и другими его сильными сторонами, JavaScript можно с уверенностью назвать лучшим языком для ознакомления с λ-исчислением.

    Топ-пост этого месяца:  Как создать бесконечную прокрутку при помощи History WebAPI

    Когда я смогу пользоваться стрелками?

    Стрелочные функции из ES6 были реализованы в Firefox мной ещё в 2013. Ян де Мойж (Jan de Mooij) сделал их быстрыми. Спасибо Тоору Фуджисава (Tooru Fujisawa) и ziyunfei за патчи.

    Стрелочные функции также реализованы в предварительной версии Microsoft Edge. Они также доступны в Babel, Traceur и TypeScript, если вы хотите начать использовать их в вебе прямо сейчас.


    Нашей следующей темой будет одна из странных особенностей ES6. Мы увидим, что typeof x возвращает совершенно новое значение. Мы зададимся вопросом: когда имя не является строкой? Мы переосмыслим понятие равенства. Это будет необычно. Так что присоединяйтесь на следующей неделе, и мы рассмотрим символы ES6 в деталях.

    [Перевод] Руководство по JavaScript, часть 8: обзор возможностей стандарта ES6 29.11.2020 14:47

    Сегодня, в восьмой части перевода руководства по JavaScript, мы сделаем обзор возможностей языка, которые появились в нём после выхода стандарта ES6. Мы, так или иначе, сталкивались со многими из этих возможностей ранее, где-то останавливаясь на них подробнее, где-то принимая как нечто само собой разумеющееся. Этот раздел руководства призван, наряду с раскрытием некоторых тем, которых мы ранее не касались, упорядочить знания начинающего разработчика в области современного JavaScript.

    → Часть 1: первая программа, особенности языка, стандарты
    → Часть 2: стиль кода и структура программ
    → Часть 3: переменные, типы данных, выражения, объекты
    → Часть 4: функции
    → Часть 5: массивы и циклы
    → Часть 6: исключения, точка с запятой, шаблонные литералы
    → Часть 7: строгий режим, ключевое слово this, события, модули, математические вычисления

    О стандарте ES6

    Стандарт ES6, который правильнее было бы называть ES2015 или ECMAScript 2015 (это — его официальные наименования, хотя все называют его ES6), появился через 4 года после выхода предыдущего стандарта — ES5.1. На разработку всего того, что вошло в стандарт ES5.1, ушло около десяти лет. В наши дни всё то, что появилось в этом стандарте, превратилось в привычные инструменты JS-разработчика. Надо отметить, что ES6 внёс в язык серьёзнейшие изменения (сохраняя обратную совместимость с его предыдущими версиями). Для того чтобы оценить масштаб этих изменений, можно отметить, что размер документа, описывающего стандарт ES5, составляет примерно 250 страниц, а стандарт ES6 описывается в документе, состоящем уже из приблизительно 600 страниц.

    В перечень наиболее важных новшеств стандарта ES2015 можно включить следующие:

    • Стрелочные функции
    • Промисы
    • Генераторы
    • Ключевые слова let и const
    • Классы
    • Модули
    • Поддержка шаблонных литералов
    • Поддержка параметров функций, задаваемых по умолчанию
    • Оператор spread
    • Деструктурирующее присваивание
    • Расширение возможностей объектных литералов
    • Цикл for. of
    • Поддержка структур данных Map и Set

    Рассмотрим эти возможности.

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

    Стрелочные функции изменили внешний вид и особенности работы JavaScript-кода. С точки зрения внешнего вида их использование делает объявления функций короче и проще. Вот объявление обычной функции.

    А вот практически такая же (хотя и не полностью аналогичная вышеобъявленной) стрелочная функция.

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

    Если стрелочная функция принимает лишь один параметр, записать её можно следующим образом.

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

    Особенности ключевого слова this в стрелочных функциях

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

    Это устраняет проблему, для решения которой при использовании обычных функций приходилось, для сохранения контекста, использовать конструкции наподобие var that = this . Однако, как было показано в предыдущих частях руководства, это изменение серьёзно сказывается на особенностях работы со стрелочными функциями и на сфере их применения.

    Промисы

    Промисы позволяют избавиться от широко известной проблемы, называемой «адом коллбэков», хотя их использование подразумевает применение достаточно сложных структур. Эта проблема была решена в стандарте ES2020 с появлением конструкции async/await , которая основана на промисах.

    JavaScript-разработчики использовали промисы и до появления стандарта ES2015, применяя для этого различные библиотеки (например — jQuery, q, deferred.js, vow). Это говорит о важности и востребованности данного механизма. Разные библиотеки реализуют его по-разному, появление стандарта в этой области можно считать весьма позитивным фактом.
    Вот код, написанный с использованием функций обратного вызова (коллбэков).

    С использованием промисов это можно переписать следующим образом.

    Генераторы

    Генераторы — это особые функции, которые могут приостанавливать собственное выполнение и возобновлять его. Это позволяет, пока генератор находится в состоянии ожидания, выполняться другому коду.

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

    Всё это делается благодаря единственному простому ключевому слову yield . Когда в генераторе встречается это ключевое слово — его выполнение приостанавливается.
    Генератор может содержать множество строк с этим ключевым словом, приостанавливая собственное выполнение несколько раз. Генераторы объявляют с использованием конструкции *function . Эту звёздочку перед словом function не стоит принимать за нечто вроде оператора разыменования указателя, применяемого в языках наподобие C, C++ или Go.

    Генераторы знаменуют своим появлением новую парадигму программирования на JavaScript. В частности, они дают возможность двустороннего обмена данными между генератором и другим кодом, позволяют создавать долгоживущие циклы while , которые не «подвешивают» программу.

    Рассмотрим пример, иллюстрирующий особенности работы генераторов. Вот сам генератор.

    Такой командой мы его инициализируем.

    Затем мы обращаемся к его итератору.

    Эта команда запускает итератор, она возвращает такой объект.

    Здесь происходит следующее. В коде выполняется функция, использующая значение input , переданное конструктору генератора. Код генератора выполняется до тех пор, пока в нём не встретится ключевое слово yield . В этот момент он возвращает результат деления input на 2 , что, так как input равняется 10 , даёт число 5 . Это число мы получаем благодаря итератору, и, вместе с ним, указание на то, что работа генератора пока не завершена (свойство done в объекте, возвращённом итератором, установлено в значение false ), то есть, функция пока лишь приостановлена.
    При следующем вызове итератора мы передаём в генератор число 7 .

    В ответ на это итератор возвращает нам следующий объект.

    Здесь число 7 было использовано при вычислении значения doubleThat .

    На первый взгляд может показаться, что код input / 2 представляет собой нечто вроде аргумента некоей функции, но это — лишь значение, возвращаемое на первой итерации. Здесь мы это значение пропускаем и используем новое входное значение 7 , умножая его на 2 . После этого мы доходим до второго ключевого слова yield , в результате значение, полученное на второй итерации, равняется 14 .

    На следующей итерации, которая является последней, мы передаём в генератор число 100 .

    В ответ получаем следующий объект.

    Итерация завершена (в генераторе больше не встречается ключевое слово yield ), в объекте возвращается результат вычисления выражения (input * doubleThat * another) , то есть — 10 * 14 * 100 и указание на завершение работы итератора ( done: true ).

    Ключевые слова let и const

    В JavaScript для объявления переменных всегда использовалось ключевое слово var . Такие переменные имеют функциональную область видимости. Ключевые слова let и const позволяют, соответственно, объявлять переменные и константы, обладающие блочной областью видимости.

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

    Ключевое слово const работает так же как и let , но с его помощью объявляют константы, которые являются иммутабельными.

    В современном JS-коде ключевое слово var используется редко. Оно уступило место ключевым словам let и const . При этом, что может показаться необычным, ключевое слово const используется сегодня весьма широко, что говорит о популярности идей иммутабельности сущностей в современном программировании.

    Классы

    Сложилось так, что JavaScript был единственным чрезвычайно широко распространённым языком, использующим модель прототипного наследования. Программисты, переходящие на JS с языков, реализующих механизм наследования, основанный на классах, чувствовали себя в такой среде неуютно. Стандарт ES2015 ввёл в JavaScript поддержку классов. Это, по сути, «синтаксический сахар» вокруг внутренних механизмов JS, использующих прототипы. Однако это влияет на то, как именно пишут JS-приложения.

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

    Эта программа выводит в консоль текст Hello, I am Tom Cruise. I am an actor .
    В JS-классах нельзя объявлять переменные экземпляров, их нужно инициализировать в конструкторах.

    ▍Конструктор класса

    У классов есть специальный метод, constructor , который вызывается при создании экземпляра класса с использованием ключевого слова new .

    ▍Ключевое слово super

    Ключевое слово super позволяет обращаться к родительскому классу из классов-потомков.

    ▍Геттеры и сеттеры

    Геттер для свойства можно задать следующим образом.

    Сеттер можно описать так, как показано ниже.

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

    Модули

    До появления стандарта ES2015 существовало несколько конкурирующих подходов к работе с модулями. В частности, речь идёт о технологиях RequireJS и CommonJS. Такая ситуация приводила к разногласиям в сообществе JS-разработчиков.

    В наши дни, благодаря стандартизации модулей в ES2015, ситуация постепенно нормализуется.

    ▍Импорт модулей

    Модули импортируют с использованием конструкции вида import. from. . Вот несколько примеров.

    ▍Экспорт модулей

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

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

    Шаблонные литералы представляют собой новый способ описания строк в JavaScript. Вот как это выглядит.

    Кроме того, использование синтаксиса шаблонных литералов позволяет внедрять в строки выражения, интерполировать их. Делается это с помощью конструкции вида $ . Вот простой пример её использования:

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

    Благодаря использованию шаблонных литералов гораздо легче стало объявлять многострочные строки.

    Сравните это с тем, что приходилось делать для описания многострочных строк при использовании возможностей, имевшихся в языке до ES2015.

    Параметры функций, задаваемые по умолчанию

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

    Оператор spread

    Оператор spread (оператор расширения) позволяет «раскрывать» массивы, объекты или строки. Этот оператор выглядит как три точки ( . ). Сначала рассмотрим его на примере массива.

    Вот как на основании этого массива создать новый массив.

    Вот как создать копию массива.

    Этот оператор работает и с объектами. Например — вот как с его помощью можно клонировать объект.

    Применив оператор spread к строке, можно преобразовать её в массив, в каждом элементе которого содержится один символ из этой строки.

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

    Раньше это делалось с использованием конструкции вида f.apply(null, a) , но такой код и писать сложнее, и читается он хуже.

    Деструктурирующее присваивание

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

    Здесь из объекта извлекаются свойства firstName и age . Свойство age записывается в объявляемую тут же константу с таким же именем, а свойство firstName , после извлечения, попадает в константу name .

    Деструктурирующее присваивание подходит и для работы с массивами.

    В константы first , second и fifth попадут, соответственно, первый, второй и пятый элементы массива.

    Расширение возможностей объектных литералов

    В ES2015 значительно расширены возможности описания объектов с помощью объектных литералов.

    ▍Упрощение включения в объекты переменных

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

    Теперь то же самое можно сделать так.

    ▍Прототипы

    Прототип объекта теперь можно задать с помощью следующей конструкции.

    ▍Ключевое слово super

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

    ▍Вычисляемые имена свойств

    Вычисляемые имена свойств формируются на этапе создания объекта.

    Цикл for…of

    В 2009 году, в стандарте ES5, появились циклы forEach() . Это — полезная конструкция, к минусам которой относится тот факт, что такие циклы очень неудобно прерывать. Классический цикл for в ситуациях, когда выполнение цикла нужно прервать до его обычного завершения, оказывается гораздо более адекватным выбором.

    В ES2015 появился цикл for. of , который, с одной стороны, отличается краткостью синтаксиса и удобством forEach , а с другой — поддерживает возможности по досрочному выходу из цикла.

    Вот пара примеров цикла for. of .

    Структуры данных Map и Set

    В ES2015 появились структуры данных Map и Set (а также их «слабые» варианты WeakMap и WeakSet , использование которых позволяет улучшить работу «сборщика мусора» — механизма, ответственного за управление памятью в JS-движках). Это — весьма популярные структуры данных, которые, до появлениях их официальной реализации, приходилось имитировать имеющимися средствами языка.

    Итоги

    Сегодня мы сделали обзор возможностей стандарта ES2015, которые чрезвычайно сильно повлияли на современное состояние языка. Нашей следующей темой будут особенности стандартов ES2020, ES2020 и ES2020.

    Уважаемые читатели! Какие новшества стандарта ES6 кажутся вам наиболее полезными?

    Новые возможности ES2020 о которых должен знать каждый разработчик JavaScript

    Девятое издание стандарта ECMAScript, официально известного как ECMAScript 2020 (или ES2020 для краткости), было выпущено в июне 2020 года. Начиная с ES2020, новые версии спецификаций ECMAScript выпускаются ежегодно, а не раз в несколько лет, и содержат меньше новых возможностей, чем основные редакции. Новейшая версия стандарта продолжает ежегодный цикл выпуска. В нем было добавлено четыре новых функции RegExp, свойства rest/spread, асинхронную итерацию и Promise.prototype.finally. Кроме того, ES2020 отменяет синтаксическое ограничение escape-последовательностей из тегированных шаблонов.

    Описание этих новые возможностей объясняются в следующих подразделах.

    Свойства rest/spread

    Одно из наиболее интересных свойств добавленных в ES2015 был оператор spread. Этот оператор делает операции копирования и объединения массивов намного легче. Вместо вызова методов concat() или slice() , можно просто использовать оператор . :

    Оператор spread так же удобен в ситуациях массив должен быть передан в качестве отдельного аргумента в функцию. Для примера:

    ES2020 дополнительно расширяет этот синтаксис, добавляя свойства spread к литеральным объектам. С помощью свойств spread вы можете скопировать собственные перечисляемые свойства объекта в новый объект. Рассмотрим следующий пример:

    В коде, оператор . был использован для получения свойств объекта obj1 и назначению их объекту obj2 . До появления ES2020, подобная конструкция вызвала бы ошибку. Если будут определены несколько свойств с одинаковыми именами то останутся только те которые были последними:

    Свойство spread так же предоставляет новый путь объединения двух и более объектов, вместо использования метода Object.assign() :

    Однако обратите внимание, что оператор spread не всегда дает тот же результат что и Object.assign() . Рассмотрим следующий код:

    В этом коде, метод Object.assign() вызывает унаследованое свойство сеттера. И наоборот, оператор spread игнорирует свойство сеттера.

    Важно понимать, что оператор spread копирует только перечисляемые свойства.

    В следующем примере, свойство type не будет скопировано потому что его атрибут enumerable установлен в false :

    Унаследованные свойство так же игнорируются даже если они перечисляемые:

    В этом коде, car2 наследует совойство color от car . Так как оператор spread копирует только собственные свойство объекта, color не копируется.

    Так же имейте в виду что оператор spread может сделать только поверхностную копию объекта. Если свойство содержит объект, будет скопирована только ссылка на объект:

    Свойство x в copy1 ссылается на тоже самый объект в памяти что и x в copy2 , поэтому оператор сравнения возвращает true .

    Еще одна полезная функция, добавленная в ES2015, – это rest параметры, которые позволяют использовать для представления значений как массив. Например:

    Здесь, первый элемент в arr назначен переменной x , а оставшиеся элементы назначены переменной rest . Этот паттерн, называемый деструктуризацией массива, стал настолько популярным, что технический комитет Ecma решил привнести аналогичную функциональность в объекты:

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

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

    Поддержка свойств Rest/Spread

    Chrome Firefox Safari Edge
    60 55 11.1 No
    Chrome Android Firefox Android iOS Safari Edge Mobile Samsung Internet Android Webview
    60 55 11.3 No 8.2 60

    Node.js:

    • 8.0.0 (требует флаг —harmony )
    • 8.3.0 (полная поддержка)

    Асинхронная итерация

    Перебор набора данных является важной частью программирования. До ES2015 JavaScript предоставлял для этой цели операторы for, for … in и while, а также такие методы, как map(), filter() и forEach(). Чтобы программисты могли обрабатывать элементы коллекции по одному, в ES2015 появился интерфейс итератора.

    Объект является итеративным, если у него есть свойство Symbol.iterator. В ES2015 объекты строк и коллекций, такие как Set, Map и Array, имеют свойство Symbol.iterator и, следовательно, являются итеративными. Следующий код дает пример того, как получить доступ к итерируемым элементам:

    Symbol.iterator – это широко известный символ, определяющий функцию, которая возвращает итератор. Основным способом взаимодействия с итератором является метод next(). Этот метод возвращает объект с двумя свойствами: value и done. Свойство value содержит значение следующего элемента в коллекции. Свойство done содержит true или false, указывающие, достигнут ли конец коллекции.

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

    Этот объект является итеративным, поскольку у него определенно свойство Symbol.iterator. Итератор использует метод Object.keys() для получения массива имен свойств объекта, а затем присваивает его константе values. Он также определяет переменную-счетчик и присваивает ему начальное значение 0. При выполнении итератора он возвращает объект, содержащий метод next(). Каждый раз, когда вызывается метод next(), он возвращает пару со value, содержащим следующий элемент в коллекции, и done хранящее логическое значение, указывающее, достиг ли итератор конца в коллекции.

    Хотя этот код работает отлично, он неоправданно сложен. К счастью, использование функции генератора может значительно упростить процесс:

    Внутри этого генератора цикл for … in используется для перечисления по коллекции и получения значения каждого свойства. Результат точно такой же, как и в предыдущем примере, но код значительно короче.

    Недостатком итераторов является то, что они не подходят для работы с асинхронными источниками данных. Поэтому в ES2020 появились асинхронные итераторы и асинхронные итерируемые объекты -итерации (iterables). Асинхронный итератор отличается от обычного итератора тем, что вместо возврата простого объекта в формате он возвращает промис (promise), которое соответствует . Асинхронная итерируемые объекты (iterable) содержат метод Symbol.asyncIterator (вместо Symbol.iterator), который возвращает асинхронный итератор.

    Обратите внимание, что для достижения того же результата невозможно использовать итератор промисей (promises). Хотя обычный синхронный итератор может асинхронно определять values, он все равно должен определять состояние «done» синхронно.

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

    Обычно, функция генератор с помощью метода next() возвращает объект генератор . То есть когда вызывается next() он возвращает пару где свойство value содержит полученное значение. Асинхронный генератор делает то же самое за исключением то что он возвращает промисис (promise) которые соответствует .

    Простой способ перебора итерируемого объекта состоит в использовании оператора for … of, но for … of не работает с асинхронными итерируемыми объектами, поскольку value и done не определяются синхронно. По этой причине ES2020 предоставляет for…await…of. Давайте посмотрим на пример:

    В этом коде оператор for … await … of неявно вызывает метод Symbol.asyncIterator для объекта коллекции, чтобы получить асинхронный итератор. Каждый раз в цикле вызывается метод итератора next(), который возвращает promise. Как только promise разрешено, свойство value результирующего объекта считывается в переменную x. Цикл продолжается до тех пор, пока свойство done возвращаемого объекта не будет иметь значение true.

    Имейте в виду, что оператор for … await … of действует только в асинхронных генераторах и асинхронных функциях. Нарушение этого правила приводит к ошибке SyntaxError.

    Метод next() может вернуть promise, которое будет отклонено. Чтобы корректно обработать отклоненное обещание, вы можете заключить оператор for…await…of в оператор try…catch, например:

    Поддержка асинхронных итераторов

    Chrome Firefox Safari Edge
    63 57 12 No
    Chrome Android Firefox Android iOS Safari Edge Mobile Samsung Internet Android Webview
    63 57 12 No 8.2 63

    Node.js:

    • 8.10.0 (требуется флаг –harmony_async_iteration)
    • 10.0.0 (полная поддержка)

    Promise.prototype.finally

    Еще одно интересное дополнение в ES2020 – метод finally(). Несколько библиотек ранее реализовывали подобный метод, который оказался полезным во многих ситуациях. Это побудило технический комитет Ecma официально добавить finally() в спецификацию. С помощью этого метода можно выполнять блок кода независимо от состояния promise. Давайте посмотрим на простой пример:

    Метод finally() очень полезен когда нужно например что то очистить после операции которая может завершиться успешно или нет. В этом коде, метод finally() просто скрывает спиннер загрузки после получения данных. Вместо то что бы дублировать финальную логику в методах then() и catch() можно прописать этот код в одном методе которых выполнится независимо от статуса выполнения promises.

    Вы можете достичь такого же результата используя promise.then(func, func) вместо promise.finally(func) , но нужно будет дублировать одинаковый код в обработчике успешного и ошибочного завершения promises, ну или использовать отдельную переменную для этого:

    Как и в случае then() и catch(), метод finally() всегда возвращает promise, поэтому можно связать несколько методов. Обычно finally() используется последним элементом в цепочке, но в определенных ситуациях, например, при выполнении HTTP-запроса, рекомендуется объединить в цепочку другую функцию catch() для обработки ошибок, которые так же могут возникнуть в finally().

    Поддержка Promise.prototype.finally

    Chrome Firefox Safari Edge
    63 58 11.1 18
    Chrome Android Firefox Android iOS Safari Edge Mobile Samsung Internet Android Webview
    63 58 11.1 No 8.2 63

    Node.js:

    10.0.0 (полная поддержка)

    Новые свойства RegExp

    ES2020 добавленно четыре новых свойства объекта RegExp , которые значительно улучшают возможности обработки строк JavaScript. Новые свойства:

    • s (dotAll) флаг
    • Именованные группы
    • Ретроспективные проверки
    • Unicode property escapes

    s (dotAll) Флаг

    В регулярных выражениях точка ( . ) специальный символ который соответствует любому символу за исключением символов разрыва строки такими как перехода на новую строку ( \n ) или возврате каретки ( \r ). Обходной путь для сопоставления всех символов, включая разрывы строк, заключается в использовании класса символов с двумя противоположными сокращениями, такими как [\d\D]. Этот класс символов сообщает обработчику регулярных выражений, что нужно найти символ, который является либо цифрой ( \d ), либо не цифрой ( \D ). В результате он соответствует любому символу:

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

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

    Именованные группы

    В некоторых шаблонах регулярных выражений использование числа для ссылки на группу может привести к путанице. Например, возьмем регулярное выражение /(\d<4>)-(\d<2>)-(\d<2>)/, соответствующее дате. Поскольку нотация даты в американском английском отличается от британского английского, трудно понять, какая группа относится к дню, а какая группа относится к месяцу:

    ES2020 представляет именованные группы, которые используют синтаксис (? …). Таким образом, шаблон для сопоставления с датой можно записать менее двусмысленным образом:

    Позже вы можете вызвать именованную группу в шаблоне, используя синтаксис \k . Например, чтобы найти последовательные повторяющиеся слова в предложении, вы можете использовать /\b(? \w+)\s+\k \b/:

    Чтобы вставить именованную группу в строку замены метода replace(), нужно будет использовать конструкцию $ . Например:

    Ретроспективные проверки (Lookbehind Assertion)

    ES2020 привносит в JavaScript assertion (утверждения), которые были доступны в других реализациях регулярных выражений в течение многих лет. Ранее JavaScript поддерживал только предварительные утверждения. Ретроспективные (Lookbehind) утверждение обозначается (?

    ES2020 удаляет эти ограничения из тегированных шаблонов и вместо того, чтобы выдавать ошибку, представляет недопустимые escape-последовательности как undefined:

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

    Поддержка Template Literal Revision

    Chrome Firefox Safari Edge
    62 56 11 No
    Chrome Android Firefox Android iOS Safari Edge Mobile Samsung Internet Android Webview
    62 56 11 No 8.2 62

    Node.js:

    • 8.3.0 (требует флаг –harmony)
    • 8.10.0 (полная поддержка)

    Завершение

    Мы рассмотрели несколько ключевых функций, представленных в ES2020, включая асинхронную итерацию, свойства rest/spread, Promise.prototype.finally() и дополнения к объекту RegExp. Хотя некоторые из этих функций еще не полностью реализованы в некоторых браузерах, ими можно пользоваться благодаря транспортерам JavaScript, таким как Babel.

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

    Литерал объекта JavaScript: описание новых функций и возможностей в ES6

    И снова «ES6 изнутри». Если вы в этом цикле статей впервые, то советую изучить деструктирование, литералы шаблона, стрелочные функции или операторы расширения и оставшиеся параметры. Сегодня предлагаю познакомиться с литералами объекта в ES6. «Ну уж их-то и сейчас можно использовать» — скажете вы — литералы объекта тянутся еще аж с ES3. Эта статья про новинки ES6 для литералов объекта.

    Как и в прошлых статьях, рекомендую вам установить Babel и повторять за мной, копируя примеры с помощью REPL, либо командной строки babel-node и файла. Это поможет гораздо лучше усвоить идеи, обсуждаемые в серии. Если вы не из тех, кто любит устанавливать что-либо на свой компьютер, то вам есть смысл залезть на CodePen и кликнуть иконку с шестерёнкой для JavaScript — у него есть препроцессор Babel, который с лёгкостью позволяет опробовать ES6.

    Вперёд к неизведанному!

    Сокращённые записи значений свойства

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

    В показанном ниже снипете я воспроизвел часть localStorage в памяти в качестве полифилла. Это паттерн, который я применял несметное число раз в своём коде.

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

    • Не приходится увеличивать отступ
    • Публичный API выделяется
    • Труднее получить сильно связанные методы
    • Легче для понимания

    С ES6 в этот список можно добавить ещё один пункт — с помощью сокращённых записей значения свойства можно еще упростить экспорт. Если имя свойства совпадает с его значением, то последнее можно опустить. Таким образом, module.exports из кода выше становится:

    Динамические имена свойства

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

    Вместо обычного имени свойства, динамические имена свойств позволяют писать выражения, обёрнутые в квадратные скобки. Результат выражения, каким бы он ни был, станет именем свойства.

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

    При всём сказанном, думаю, вот наиболее типичное применение. Тут код проще, поскольку не нужны три лишних действия — заводить переменную foo , присваивать значение foo[type] и возвращать foo . Вместо этого можно сделать всё это в одном операторе.

    То что надо. Что же ещё?

    Определения методов

    Обычно в ES5 объявление методов происходит так:

    Тогда как синтаксис геттеров и сеттеров не требует ключевого слова function . Это просто вытекает из контекста.

    Начиная с ES6, можно объявлять обычные методы с похожим синтаксисом, разница лишь в отсутствии перед ними get или set .

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

    P.S. Это тоже может быть интересно:

    Если вам понравилась статья, поделитесь ей!

    Обзор функций в JavaScript ES6

    В течение последних нескольких лет JavaScript изменялся. И вот 12 новых фичей, которые вы можете начать использовать уже сегодня!

    1. История JavaScript

    Новые дополнения к языку называются ECMAScript 6. Они также упоминаются как ES6 или ES2015+. Начиная с концепции 1995 года, JavaScript развивался медленно. Новые дополнения выходили раз в несколько лет. ECMAScript появился в 1997 году, чтобы указать путь JavaScript. Были выпущены такие его версии: ES3, ES5, ES6 и другие.

    Как вы заметили, между ES3, ES5 и ES6 существуют промежутки в 10 и 6 лет. Новая стратегия состоит в том, чтобы делать небольшие постепенные изменения каждый год. Вместо того, чтобы делать большие изменения сразу, как это случилось с ES6.

    2. Поддержка браузеров

    Все современные браузеры и среды программирования уже поддерживают ES6!

    Chrome, MS Edge, Firefox, Safari, Node и многие другие уже имеют встроенную поддержку большинства функций JavaScript ES6. Таким образом, всё, что вы собираетесь изучить в этом туториале, вы можете начать использовать прямо сейчас. Давайте начнем с ECMAScript 6!

    3. Основные функции ES6

    Вы можете проверить все эти фрагменты кода на консоли своего браузера.

    Так что не верьте мне на слово и тестируйте каждый пример ES5 и ES6.

    3.1. Блочная область видимости переменных

    В ES6 мы перешли от объявления переменных с var на использование let/const.

    Что не так с var? Проблема var – это утечка переменной в другой блок кода, например, в циклы for или if-блоки.

    Для test(false) вы ожидаете возвращения outer, но нет, вы получаете undefined. Почему?

    Потому что даже при том, что if-блок не выполняется, выражение var x в строке 4 «поднимается».

    Поднятие переменных:

    • var является переменной области видимости. Она доступна во всей функции даже до того, как её объявят.
    • Выражения «поднимаются». Так что вы сможете использовать переменные до их объявления.
    • Инициализация НЕ поднимется. Если вы используете var, ВСЕГДА объявляйте ваши переменные наверху.
    • После применения правил подъема, мы можем лучше понять, что же случилось.
    • ECMAScript 2015 идёт на помощь:

    Изменение var на let приводит к тому, что всё работает так, как и ожидалось. Если блок if не вызывается, переменная x не поднимается из блока.

    Взглянём на поднятие и «временные мёртвые зоны»:

    • В ES6 let будет поднимать переменную наверх блока (НЕ наверх функции, как это происходит в ES5).
    • Однако ссылка на переменную в блоке перед объявлением этой переменной приводит к ReferenceError.
    • let – переменная области видимости. Вы не можете использовать её, пока она не будет объявлена.
    • «Временные мёртвые зоны» – это зоны в начале блока и до того места, где объявляется переменная.

    IIFE (Immediately-Invoked Function Expression)

    Перед объяснением IIFE взгляните на пример:

    Как вы видите, появляется private. Для того, чтобы удержать его, вам необходимо использовать IIFE (немедленно-вызываемое выражение функции):

    Если вы посмотрите на jQuery/lodash или другие open source проекты, то заметите, что они используют IIFE во избежание загрязнения глобальной среды и определения только глобального, например _,$ или jQuery.

    ES6 гораздо проще, нам больше не нужно использовать IIFE, когда мы просто можем применить блоки и let:

    Const

    Вы также можете использовать const, если не хотите, чтобы переменная изменялась вообще.

    3.2. Литералы шаблонов

    Нам больше не нужно встраивать конкатенации, когда у нас есть литералы шаблонов. Взгляните:

    Сейчас вы можете использовать кавычку (`) и строковую интерполяцию $<>:

    3.3. Многострочные строки

    Нам больше не нужно конкатенации строк + \n по типу:

    В ES6 мы снова можем использовать кавычку для решения такого примера:

    Оба фрагмента кода будут иметь точно такой же результат.

    3.4. Назначение деструктуризации

    Деструктуризация в ES6 очень полезная и точная.

    Получение элементов с массива

    Обмен значений

    Деструктуризация для нескольких возвращаемых значений

    В строке 3 вы также можете вернуть ее в массив подобный тому, что на примере (и сохранить некоторые, набрав код):

    Но потом необходимо подумать о порядке возврата данных.

    В ES6 вызывающий выбирает только те данные, которые ему нужны (строка 6):

    Обратите внимание: В строке 3 есть некоторые другие функции ES6. Мы можем сжать < left: left>только до < left>.Посмотрите, насколько это компактнее по сравнению с версией ES5. Разве не круто?

    Деструктуризация для параметров согласования

    Так же, но короче:

    Deep Matching

    Так же, но короче:

    Это также называют деструктуризацией объектов.

    Как видите, деструктуризация весьма полезна и способствует хорошему стилю программирования.

    Практический опыт:

    • Используйте деструктуризацию массива для получения элементов или замены переменных. Это избавит вас от создания временных ссылок.
    • Не используйте деструктуризацию массива для нескольких возвращаемых значений, вместо этого примените деструктуризацию объекта.

    3.5. Классы и Объекты

    С ECMAScript 6 мы перешли от «функции-конструктора» к «классам».

    В JavaScript каждый отдельный объект имеет прототип, который является другим объектом. Все объекты JavaScript наследуют свои методы и свойства от своего прототипа.

    В ES5 мы использовали объектно-ориентированное программирование (ООП), применяя функцию- конструктор для создания объектов, следующим образом:

    В ES6 имеется некий синтаксический сахар. Мы можем делать то же самое менее шаблонно и с новыми ключевыми словами, такими как >

    Как видим, оба стиля (ES5/6) дают одинаковые результаты и используются одинаково.

    Практический опыт:

    • Всегда используйте синтаксис класса и избегайте прямого манипулирования прототипом. Почему? Потому что это делает код более кратким и понятным.
    • Избегайте наличия пустого конструктора. Классы имеют конструктор по умолчанию, если он не указан.

    3.6. Наследование

    Опираемся на предыдущий класс Animal. Предположим, мы хотим расширить его и определить класс Lion.

    В ES5 это большей частью связано с прототипическим наследованием.

    Я не буду описывать все детали, но заметьте:

    • В строке 3 мы явно вызываем конструктор Animal с параметрами.
    • В строках 7-8 мы назначили прототип Lion прототипу Animal.
    • В строке 11 мы вызываем метод speak из родительского класса Animal.

    В ES6 у нас есть новые ключевые слова extends и super.

    Посмотрите, насколько разборчиво выглядит этот код ES6 по сравнению с ES5, и они работают одинаково!

    • Используйте встроенный способ наследования с extends.

    3.7. Native Promises

    Мы перешли от callback hell к promises.

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

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

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

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

    ES6 не удалил выражения функций, но добавил новые функции – стрелочные.

    В ES5 были некоторые проблемы с this:

    Вам нужно использовать временное this для ссылки внутри функции или использовать bind. В ES6 вы можете использовать стрелочную функцию.

    3.9. For…of

    Мы перешли от for к forEach, и потом к for…of:

    В ES6 for. of также позволяет нам делать итерации.

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

    Мы перешли от проверки того, была ли переменная определена, к присвоению значения параметрам по умолчанию (default parameters). Вы делали что-то подобное раньше?

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

    • В строке 8 мы задали 0, 0 и получили 0, -1
    • В строке 9 мы задали false, но получили true.

    Если в качестве параметра по умолчанию задано значение boolean или это значение равно нулю, то оно не будет работать. Знаете почему? Все расскажем после примера ES6. С ES6 вы можете писать код лучше и короче!

    Обратите внимание на строки 5 и 6 – мы получаем ожидаемые результаты. Пример ES5 не работает. Сначала мы должны проверить undefined, поскольку false, null, undefined и 0 являются фальшивыми значениями. Мы можем выбраться с такими цифрами:

    Сейчас всё работает так, как и должно, когда мы проверяем undefined.

    3.11. Rest-параметры

    Мы перешли от аргументов к rest-параметрам и spread-оператору. Получать произвольное количество аргументов на ES5 довольно неудобно:

    Мы можем сделать то же, используя rest-оператор . . . .

    3.12. Spread-оператор

    Мы пришли от apply() до spread-оператора. Опять на помощь приходит . . .:

    Напоминание: мы используем apply () для преобразования массива в список аргументов. Например, Math.max () принимает список параметров, но, если у нас есть массив, мы можем использовать apply, чтобы заставить его работать.

    Как мы видели ранее, мы можем использовать apply для передачи массивов в виде списка аргументов:

    В ES6 вы можете использовать spread-оператор:

    Кроме того, мы пришли от использования массивов contact к использованию spread-оператора:

    В ES6 вы можете сглаживать вложенные массивы, используя оператор spread:

    4. Заключение

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

    Материал подготовлен на основе статьи из блога Adrian Mejia

    Создайте литерал шаблона ES6 с функцией

    У меня есть строка, которая содержит шаблонные литералы, но не является литералом шаблона из-за его динамического построения. Я хотел бы преобразовать его в шаблон «literal», не делая eval() :

    Я ищу доступ к внутреннему построителю шаблонов в духе класса RegExp, который можно использовать вместо стандартных реляционных слэшей регулярного выражения // :

    Таким образом я мог бы сделать:

    Вы не можете «построить литерал». Это противоречие в терминах. Литерал — это синтаксис исходного кода, который компилируется в значение.

    new RegExp(. ) создает новый объект regexp, но не литерал регулярного выражения. Регламент REGExp — это когда вы буквально пишете /. / .

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

    EDIT: Быстрая и грязная:

    Однако, в то время как new Function всегда лучше, чем eval , применяются обычные отказы в выполнении ненадежных строк.

    Для более безопасной альтернативы см. Mustache.js или Pug.js (а не Pod, как я сказал в комментарии, извините), как ведущие библиотеки шаблонов JavaScript.

    Ключевая проблема здесь заключается в том, что у вас есть в вашем комментарии в первом блоке кода:

    это динамически создается алгоритмом

    Если шаблон создан по алгоритму, ваши варианты:

    • Не используйте встроенную функцию шаблона, используйте любую из нескольких похожих библиотек шаблонов (или напишите сами)
    • Используйте eval или одного из его кузенов (возможно, new Function )

    Динамические шаблоны шаблонов нельзя создавать динамически. Это литералы. 🙂

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

    Добавить комментарий