Урок 10. ES6 (EcmaScript 6). Классы


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

Урок 10. ES6 (EcmaScript 6). Классы

Категория имеет мидийных объектов числом 17

Видеокурс JavaScript Advanced. Урок 10. AJAX и HTTP протокол

В этом уроке мы познакомим вас с новым стандартом JavaScript – ECMAScript 6, который является дополнением к существующей спецификации и существенно расширяет возможности веб разработчика. Мы подготовили короткий обзор нововведений с комментариями о том, как их лучше использовать в своих проектах с учетом их поддержки браузерами. Также мы подготовим небольшую webpack сборку для работы с ES6, добавим в него babel для транспиляции из ES6 в ES5 и узнаем, зачем это все нужно.

Чтобы ознакомится с полным курсом используй промо-код (см. выше) и получи скидку.

Классы в ES6

Классы являются основой объектно-ориентированное программирование но не в JavaScript.

В объектно-ориентированное программирование наследование основано на прототипах объектов, а не на классах.

Если вы когда-нибудь писали код на Java Script имитируя классы, ты уверен согласитесь синтаксис не самый элегантный и простой.

С появлением es6 JavaScript наконец-то добавлена поддержка классов. Новый синтаксис не вводит новую объектно-ориентированная модель наследования, внутри используется всё те же прототипы.

Синтаксис классов это так называемый syntactic Sugar или синтаксический сахар, который призван немного подсластить, то есть упростить работу с классами и наследованием в JavaScript.

Сегодня мы рассмотрим новый синтаксис классов, а в следующем посте — наследование.

Первое, что мы сделаем, это запустим скрипт Babel, который будет следить за файлами и при их изменении создавать свежие версии.

Откроем папку проекта в командной строке (КС). Вводим команду:

Классы 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 Русаков Михаил Юрьевич. Все права защищены.

    Frontender Magazine

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

    1. Обзор

    2. Основы

    2.1 Базовые классы

    Классы определяются в ECMAScript 6 (ES6) следующим образом:

    Использовать этот класс можно просто вызвав конструктор функции, как в ES5:

    По факту, результатом создания такого класса будет функция:

    Однако, вы можете вызывать класс только через new , а не через вызов функции (Секция 9.2.2 в спецификации):

    Объявления классов не поднимаются

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

    В отличие от функций, определения классов не поднимаются. Таким образом, класс существует только после того, как его определение было достигнуто и выполнено. Попытка создания класса до этого момента приведет к «ReferenceError»:

    Причина этого ограничения в том, что классы могут быть наследниками. Это поддерживается с помощью выражения «extends», значение которого может быть произвольным. Это выражение должно быть установлено в определенном месте, которое не может быть поднято.

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

    Выражения класса

    Так же, как и для функций, есть два способа определить класс: объявление класса и выражение класса.

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

    2.2 Внутри тела определения класса

    Тело класса может содержать только методы, но не свойства. Прототип, имеющий свойства, обычно считается анти-паттерном.

    «Сonstructor», статические методы, прототипные методы

    Давайте рассмотрим три вида методов, которые вы часто можете встретить в классах.

    Диаграмма объекта для это определения класса выглядит следующим образом:

    (Совет для понимания: [[Prototype]] — это отношения наследования между объектами, в то время как prototype — обычное свойство, значением которого является объект. Значение свойства prototype оператор new использует как прототип для создаваемых объектов.)

    Для начала рассмотрим псевдо-метод «constructor». Этот метод является особенным, так как он определяет функцию, которая представляет собой класс:

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

    Далее, статические методы. Статические свойства (или свойства класса) являются свойствами самого Foo . Если вы определили метод с помощью static , значит вы реализовали метод класса:

    В третьих, прототипные методы. свойства прототипа Foo являются и свойствами Foo.prototype . Это, как правило, методы, и наследуются экземплярами Foo .

    Геттеры и Сеттеры

    Синтаксис для геттеров и сеттеров такой же как и в ECMAScript 5 литералы объекта:

    MyClass используется следующим способом:

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

    Вы можете определить имя метода с помощью выражения, если поместите его в квадратные скобки. Например, следующие определения класса Foo эквивалентны:

    Некоторые специальные методы в ECMAScript 6 имеют ключи, которые являются символами 3. Механизм вычисляемых имен методов позволяют вам определять такие методы. Например, если объект имеет метод с ключом Symbol.iterator , это — итератор 4. Это означает, что его содержимое может быть итерировано циклом for-of или другими механизмами языка.

    Генераторы

    Если вы определите метод с «*» в начале, то получите метод генератор 4. Между прочим, генератор полезен для определения метода, ключом которого является Symbol.iterator . Следующий код демонстрирует, как это работает:

    2.3 Классы наследники

    Ключевое слово extends позволяет создать класс-наследник существующего конструктора (который возможно был определен с помощью класса):

    Этот класс используется как и ожидалось:

    В данном случае мы имеем два вида классов:

    • Point — это базовый класс, потому что он не имеет выражения extends .
    • ColorPoint — производный класс.

    Есть два способа использовать ключевое слово super :

    • Конструктор класса (псевдо-метод «constructor» в теле класса), использует его как вызов функции (_super(•••)_) , для того, чтобы вызвать базовый конструктор (строка A).
    • Определения методов (в объектах, заданных через литерал, или классах, статических или нет), используют это для вызова свойства (_super.prop_) , или вызова метода (_super.method(•••)_) , для ссылки на свойства базового класса (строка B).
    Топ-пост этого месяца:  Двухфакторная аутентификация в Инстаграме как включить или отключить

    Прототип класса наследника является базовым классом

    Прототип класса наследника является базовым классом в ECMAScript 6:

    Это означает, что статические свойства наследуются:

    Можно вызывать статические методы базового класса:

    Вызов базового конструктора

    В классе-наследнике нужно вызвать super() до того, как будете обращаться к свойствам через this :

    Пропустив вызов super() в производном классе, вы получите ошибку:

    Переопределение результата конструктора

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

    Если вы так сделаете, то не имеет значения, инициализирован ли this или нет. Другими словами: вы не обязаны вызывать super() в производном конструкторе, если переопределите результат таким образом.

    Конструкторы по умолчанию для классов

    Если не указать constructor для базового класса, тогда используется следующая конструкция:

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

    Наследования встроенных конструкторов

    В ECMAScript 6 наконец-то можно наследоваться от всех встроенных конструкторов (обходные пути в ES5, но здесь накладываются значительные ограничения).

    Например, теперь вы можете создавать свои собственные классы исключений (которые будут наследовать такие особенности, как стек вызовов для большинства браузерных движков):

    Вы также можете наследоваться от Array , экземпляры которого правильно работают с length :

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

    3. Детали классов

    То, что мы до сих пор рассматривали, является основой классов. Если вам интересно узнать подробнее про механизм классов, то вам нужно читать дальше. Давайте начнем с синтаксиса классов. Ниже приводится немного модифицированная верcия синтаксиса, предложенного в Секции A.4 спецификации ECMAScript 6.

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

    Между методами допускается точка с запятой.

    3.1 Различные проверки

    Проверки ошибок: имя класса не может быть eval или arguments ; одинаковые имена классов не допускаются; название constructor может использоваться только для обычных методов, для геттеров, сеттеров и генераторов — не допускается.

    Классы не могут быть вызываемой функцией. Иначе они бросают исключение TypeException

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

    3.2 Атрибуты свойств

    Определения класса создают (изменяемые) разрешаемые связи. Для данного класса Foo :

    Статические методы Foo.* доступны для записи и настройки, но не для перечисления. Доступность для записи позволяет динамически вносить изменения в них.

    Конструктор и объект в свойстве prototype имеют неизменяемые ссылки:

    • Foo.prototype не доступен для записи, перечисления и настройки.
    • Foo.prototype.constructor не доступен для записи, перечисления и настройки.

    Прототипные методы Foo.prototype.* доступны для записи и настройки, но не для перечисления.

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

    4. Детали наследования классов

    В ECMAScript 6, наследование классов выглядит следующим образом:

    Этот код создает следующие объекты:

    Следующий подраздел рассматривает цепочки прототипов (в две колонки), далее рассматривает как cp выделяется в памяти и инициализируется.

    4.1 Цепочки прототипов

    На диаграмме видно, что есть 2 цепочки прототипов (объекты связаны через отношения [[Prototype]] , которые наследуются):

    Левая колонка: классы (функции). Прототипом производного класса является расширяемый класс. Прототип базового класса является Function.prototype , которая также есть прототип функции:

    Правая колонка: цепочки прототипов экземпляров. Цель класса — установить эту цепочку прототипов. Цепочка прототипов заканчивается на Object.prototype (чей прототип является null ), который также прототип объектов, созданных через литералы объекта:

    Из цепочки прототипов в левой колонке следует, что статические свойства наследуются.

    4.2 Выделение памяти и инициализация экземпляров объектов

    Потоки данных между конструкторами классов отличаются от канонического пути наследования в ES5. Под капотом это выглядит примерно так:

    В ES5 и ES6 экземпляр объекта создается в разных местах:

    • В ES6 он создается базовым конструктором, последним в цепочке вызовов конструкторов.
    • В ES5 он создается оператором new , первым в цепочке вызовов конструкторов.

    Предыдущий код использует две новые возможности ES6:

    new.target является неявным параметром, который имеют все функции. Это вызов конструктора, где this является вызовом метода.

    • Если конструктор напрямую вызывается через new , его значение это и есть этот конструктор (строка B).
    • Если конструктор был вызван через super() , его значение это new.target конструктора, который был вызван (строка A).
    • Вызвав функцию обычным способом, значение будет undefined . Это значит, что вы можете использовать new.target чтобы определить, была ли функция функцией вызова или вызовом конструктора (через new ).
    • Внутри стрелочной функции new.target ссылается на new.target окружающей нестрелочной функции.

    Reflect.construct() 5 позволяет вызвать конструктор при задании new.target в качестве последнего параметра.

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

    Проверки безопасности

    • this инициализируется в производных конструкторах, а это значит, что если к this обращаются до того как вызвали super() , то будет брошено исключение.
    • Вызов super() после инициализации this приведет к ReferenceError . Это защита от двойного вызова super() .
    • Если конструктор возвращается неявно (без return ), тогда результат будет this . Если this инициализирован, тогда бросится исключение ReferenceError . Это защита от невызова super() .
    • Если конструктор явно возвращает не объект (включая undefined и null ), результатом будет this (это поведение оставляет совместимость с ES5 и ранее). Если this инициализирован, тогда бросится исключение TypeError .
    • Если конструктор явно возвращает объект, тогда он и будет результатом. Тогда не имеет значение инициализирован this или нет.

    Выражение «extends»

    Давайте рассмотрим, как выражение extends влияет на работу класса (Секция. 14.5.14 спецификации).

    Значение extends должно быть «конструктивно» (вызываться через new ) хотя null тоже поддерживается.

    • Тип конструктора: базовый
    • Прототип C : Function.prototype (как обычная функция)
    • Прототип C.prototype : Object.prototype (который также прототип объекта, созданный через литералы объекта)
    • Тип конструктора: наследник
    • Прототип C : B
    • Прототип C.prototype : B.prototype
    • Тип конструктора: наследник
    • Прототип C : Object
    • Прототип C.prototype : Object.prototype

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

    • Тип конструктора: наследник
    • Прототип C : Function.prototype
    • Прототип C.prototype : null

    Такой класс бесполезный: вызов через new приведет к ошибке, потому что конструктор по умолчанию сделает вызов базового конструктора и
    Function.prototype (базовый конструктор) не может быть конструктором вызова. Единственный способ избежать ошибки — это добавить конструктор, который возвратит объект.

    4.3 Почему мы не можем наследовать встроенные конструкторы в ЕS5?

    В ECMAScript 5, большинство встроенных конструкторов не могут быть унаследованы (несколько обходных путей).

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

    К сожалению, если мы создадим MyArray , мы поймем, что он не работает должным образом: экземпляр свойства length не изменится в ответ на наше добавление элементов в массив:

    Есть два препятствия, которые мешают myArr быть правильным массивом.

    Первое препятствие: инициализация. this , который вы передаете в конструктор Array (в строке A) полностью игнорируется. Это значит, что вы не можете использовать Array чтобы настроить экземпляр, который создал MyArray .

    Второе препятствие: выделение памяти. Экземпляры объектов, созданные через Array являются экзотичными (термин, используемый в спецификации ECMAScript для объектов, которые имеют особенности, которые нормальные объекты не имеют): их свойства length отслеживают и влияют на управление элементами массива. В общем, экзотические объекты могут быть созданы с нуля, но вы не можете преобразовать существующий обычный объект в экзотический. К сожалению, это то, что делает Array , когда вызывается на строке A: Он должен был превратить обычный объект, созданный из MyArray в экзотический объект массива.

    Решение: ES6 наследование

    В ECMAScript 6, наследование Array выглядит следующим образом:

    Это работает (но это не то, что ES6 транспайлеры могут поддерживать, это зависит от того, поддерживает ли движок JavaScript это изначально):

    Сейчас рассмотрим, как подход к наследованию в ES6, позволяет обойти препятствия:

    Выделение памяти происходит в базовом конструкторе. Это значит, что Array может выделить в памяти экзотический объект. В то время как большая часть нового подхода связана с тем, как полученные конструкторы ведут себя, этот шаг требует, чтобы базовый конструктор понимал new.target и делал new.target.prototype прототипом выделенного экземпляра.

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

    4.4 Ссылка на базовые свойства в методах

    Следующий ES6 код вызывает базовый метод со строкой «B» в качестве аргумента.

    Чтобы понять как работает базовые вызовы, давайте взглянем на диаграмму объекта cp :

    ColorPoint.prototype.toString делает вызов метода базового класса (строка B) (начиная со строки A), который переопределен. Давайте вызовем объект, в котором хранится этот метод, домашний объект. Например, ColorPoint.prototype — это домашний объект для ColorPoint.prototype.toString() .


    Вызов базового класса на строке B состоит из трёх этапов:

    Начинается поиск в прототипе домашнего объекта текущего метода.

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

    Вызвать этот метод с текущим this . Причина почему это происходит: метод вызываемый как базовый должен иметь возможность доступа к тем же свойствам экземпляра (в нашем примере, к свойствам cp ).

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

    Давайте реализуем эти шаги в трех различных, но эквивалентных способах:

    Способ 3 показывает, как в ECMAScript 6 обрабатываются вызовы базового класса. Этот подход поддерживается двумя внутренними привязками, которые имеют состояния функций (состояние обеспечивает хранилище, так называемые привязки, для переменных окружения):

    • [[thisValue]] : Эта внутренняя привязка также есть и в ECMAScript 5 и хранит значение переменной this .
    • [[HomeObject]] : Относится к домашнему объекту состояния функции. Заполняется через внутреннее свойство [[HomeObject]] которое имеют все функции, использовавшие super . И привязка и свойство являются новыми в ECMAScript 6.

    Определение метода в литерале класса, который использует super , теперь имеет особенность: это значение все еще функция, но имеет внутреннее свойство [[HomeObject]] . Это свойство устанавливается определением метода и не может быть изменено в JavaScript. Таким образом, вы не можете перенести этот метод в другой объект.

    Использование super не допускается для обращения к свойству в определениях функций, выражениях функций и генераторах.

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

    Топ-пост этого месяца:  Оптимизация CSS несколько советов для повышения производительности сайта

    5. Пояснение вызовов конструктора через JavaScript код

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

    5.1 Внутренние переменные и свойства

    Спецификация описывает внутренние переменные и свойства в двойных скобках ( [[Foo]] ). В коде я использую двойные подчеркивания вместо этого ( __Foo__ ).

    Внутренние переменные используемые в коде:

    • [[NewTarget]] : Операнд оператора new , который запускает текущий вызов конструктора (передается, если [[Construct]] вызывается рекурсивно через super() ).
    • [[thisValue]] : Хранит значение this .
    • [[FunctionObject]] : Ссылается на функцию, которая в настоящее время выполняется.

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

    • [[Construct]] : Все функции конструктора (включая также созданные классом) имеют этот собственный (не наследуемый) метод. Он реализует вызов конструктора и вызывается через new .
    • [[ConstructorKind]] : Свойство функций конструктора значение которого либо «base» либо «derived».

    5.2 Состояния

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

    5.3 Вызов конструктора

    Давайте начнем с основ (ES6 спецификация, Секция. 9.2.3), где вызовы конструктора обрабатываются для функций:

    5.4 Вызов базового конструктора

    Вызов базового конструктора обрабатывается следующим образом (ES6 спецификация, Секция. 12.3.5.1).

    6. Шаблон разновидностей

    Еще один механизм встроенных конструкторов был расширен в ECMAScript 6: если метод, такой как Array.prototype.map() , возвращает экземпляр, то какой конструктор следует использовать для создания этого экземпляра? По умолчанию, используется тот же конструктор, который создал this , но некоторые наследники могут оставаться прямым экземпляром Array . ES6 позволяет классам-наследникам переопределить значение по умолчанию с помощью так называемого шаблона разновидности:

    • При создании нового экземпляра Array , методы, такие как map() используют конструктор, хранящийся в this.constructor[Symbol.species] .
    • Если конструктор наследника Array ничего не делает, он наследует Array[Symbol.species] . Это свойство является геттером, который возвращает this .

    Вы можете изменить настройки по умолчанию, с помощью статического геттера (строка A):

    Альтернативой является использование Object.defineProperty() (вы не можете использовать присвоение, т.к. вызываете сеттер, который не существует):

    Следующие геттеры возвращают this , это означает, что такие методы как Array.prototype.map() , используют конструктор, который создал текущий экземпляр их результатов.

    • Array.get [Symbol.species]()
    • ArrayBuffer.get [Symbol.species]()
    • Map.get [Symbol.species]()
    • Promise.get [Symbol.species]()
    • RegExp.get [Symbol.species]()
    • Set.get [Symbol.species]()
    • %TypedArray%.get [Symbol.species]()

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

    7.1 Специализация функций

    Существует интересная тенденция в ECMAScript 6: ранее единственный вид функции был на трех ролях: функция, метод и конструктор. В ES6, есть еще специализация:

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

    Определения метода позволяют использовать super , определив свойство [[HomeObject]] . Функции, которые они производят, не могут быть вызываемыми конструкторами.

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

    7.2 Будущее классов

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

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

    7.3 Нужны ли классы JavaScript’у?

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

    Классы ES6 обеспечивают несколько очевидных преимуществ:

    Они обратно совместимы с большей частью текущего кода.

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

    Наследование поддерживается в языке.

    Встроенные конструкторы наследуемы.

    Теперь не нужны библиотеки, реализующие наследование; код станет более переносимым между фреймворками.

    Они обеспечивают основу для расширенной функциональности в будущем (миксины и т.п).

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

    Я закончил эту статью с классами и я рад, что они есть в ES6. Я бы предпочел, чтобы они были прототипными (на основе конструктора объектов 6, а не конструктора функций), но я также понимаю, что обратная совместимость является важной.

    Для дополнительного чтения

    Обратите внимание на №1 — он играл роль значимого источника информации при написании этой статьи.

    Почему классы в ES6 такие убогие?

    Здравствуйте.
    Интересуюсь новым стандартом ES6. Посмотрел на реализацию классов и разочаровался. Больше всего не понравилось то, что в новом стандарте нельзя объявлять поля в теле объявления класса. Даже в ES5 мы могли в функции конструкторе имитировать приватные поля с помощью замыкания.

    Посмотрел на быдлокодерские приёмы с использованием Symbol и WeakMap для имитации приватности в ES6 и всё равно остался недоволен.

    Почему ES6 классы такие недоделанные? Сделали бы хотя бы как в TypeScript. Хоть там private и не приватный, но хоть нормальные поля есть.

    Курс Modern Javascript

    Курс программирования Modern Javascript

    Этот курс обучает современному Javascript в версиях ES6, ES7, ES8. Без знаний из этого курса, вы не сможете полноценно освоить современные javascript фреймворки и библиотеки, такие как ReactJS, VueJS, а также серверные технологии, такие как NodeJS.

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

    Ориентировочная дата выхода нового урока — 23.11.2020

    О курсе

    Начиная с версии ES6 Javascript заметно преобразился, в нем появились новые ключевые слова, такие как let, cons, class и другие. Синтаксис стал более красивым и в этом курсе вы испытаете в интерактивных упражнениях новые возможности Modern Javascript.

    ECMAScript 6 (2015)

    ECMAScript 6 также известен как ES6 и ECMAScript 2015.

    Некоторые предпочитают называть его JavaScript 6.

    В этой главе мы рассмотрим некоторые новые особенности ES6.

    • Ключевое слово let
    • Ключевое слово const
    • Значения параметров по умолчанию
    • Оператор возведения в степень (**) (ECMAScript 2020)
    • Метод Array.find()
    • Метод Array.findIndex()

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

    Ключевое слово let позволяет декларировать переменные внутри области видимости блока, ограниченной фигурными скобками < >.

    Так, повторная декларация переменной при помощи ключевого слова var может привести к проблеме:

    Повторная же декларация переменной при помощи ключевого слова let решает эту проблему:

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

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

    По действию оно похоже на ключевое слово let, только значение такой переменной нельзя изменять.

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

    Подробнее о ключевых словах let и const см. главы Ключевое слово let и Ключевое слово const.

    Значения параметров по умолчанию

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

    Оператор возведения в степень

    Оператор возведения в степень (**) возводит первый операнд в степень, заданную вторым операндом:

    Выражение x ** y дает тот же результат, что использование метода Math.pow(x,y):

    Метод Array.find()

    Метод find() возвращает значение первого элемента массива, прошедшего заданную проверку в функции обратного вызова.

    В следующем примере происходит поиск (и возврат значения) первого элемента, значение которого больше 18:

    Функция обратного вызова принимает 3 параметра:

    • Значение элемента (value)
    • Индекс элемента (index)
    • Сам массив (array)

    Метод Array.findIndex()

    Метод findIndex() возвращает индекс первого элемента массива, прошедшего заданную проверку в функции обратного вызова.

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

    Функция обратного вызова принимает 3 параметра:

    • Значение элемента (value)
    • Индекс элемента (index)
    • Сам массив (array)

    Новые свойства объекта Number

    В ES6 были добавлены новые свойства объекту Number:

    • EPSILON
    • MIN_SAFE_INTEGER
    • MAX_SAFE_INTEGER

    Новые методы объекта Number

    В ES6 было добавлено 2 новых метода объекту Number:

    Метод Number.isInteger()

    Метод Number.isInteger() возвращает true, если его параметр — целое число.

    Метод Number.isSafeInteger()

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

    Метод Number.isSafeInteger() возвращает true, если его параметр — безопасное целое число.

    Безопасными являются все целые числа в диапазоне от (253 — 1) до (253 — 1).
    Это число безопасное: 9007199254740991. Это число не безопасное: 9007199254740992.

    Новые глобальные методы

    В ES6 также было добавлено 2 новых глобальных метода:

    Метод isFinite()

    Глобальный метод isFinite() возвращает false, если его параметр имеет тип Infinity или NaN. В обратном случае возвращается true:

    Метод isNaN()

    Глобальный метод isNan() возвращает true, если его параметр имеет тип NaN. В обратном случае возвращается false:

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

    «Стрелочные» функции предоставляют короткую запись для выражений-функций.

    В выражении-функции больше не нужно использовать ключевые слова function, return и фигурные скобки :

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

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

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

    Урок 10. ES6 (EcmaScript 6). Классы

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

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

    Классы в JavaScript? Что ты имеешь в виду?

    JavaScript — прототипно-ориентированный язык, что это еще за классы в ES6? Классы — синтаксический «сахар» поверх прототипного наследования — уловка, делающая язык притягательнее для программистов, пришедших из других парадигм, и, возможно, не совсем знакомых с цепочками прототипов. Многие фичи в ES6 (такие как деструктирование), по сути, синтаксический «сахар» — и классы не исключение. Я остановился на этом подробно, поскольку так нам будет легче понять базовую технологию, стоящую за классами в ES6. Саму структуру языка не переделывали, а просто упростили работу с прототипным наследованием для тех, кто привык к классам.

    Хотя мне и не нравится термин «классы» для этой конкретной фичи, я вынужден признаться, что в действительности работать с этим синтаксисом гораздо легче, чем с синтаксисом обычного прототипного наследования в ES5, и это выигрыш для каждого — как их ни называй.

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

    Топ-пост этого месяца:  15 полезных советов в PHP

    Чтобы запустить автомобиль, вы могли бы использовать следующий кусок кода.

    Отлично. А что на счёт классов в ES6? Синтаксис очень похож на объявление объекта, только здесь впереди подставляется class Name , где Name — название класса. Здесь мы используем нотацию сигнатуры метода, которую мы обсуждали вчера при объявлении методов с помощью сокращённого синтаксиса. constructor — такой же метод-конструктор, как в ES5, так что это можно использовать для инициализации любых переменных, которые могут быть у экземпляров.

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

    У классов зачастую есть статические методы. Возьмите, к примеру, нашего старого приятеля Array . У каждого экземпляра массива есть его «персональные» методы .filter , .reduce и .map . Но и у «класса» Array есть свои статические методы, например, Array.isArray . Добавить подобные методы к «классу» Car и в ES5 довольно просто:

    В нотации ES6, с class , мы можем вставить перед методом static , по той же логике синтаксиса, что у get и set . Опять же, лишь «сахар» для ES5, поскольку перевести это в синтаксис старой версии не составляет труда.

    Дополнительную сладость «сахарку» class в ES6 придает то, что в придачу к нему идет ключевое слово extends, дающее возможность легко «наследоваться» от других «классов». Мы знаем, что Тесла проезжает больше на том же количестве топлива, и в коде ниже видно, как класс Tesla расширяет класс Car ( Tesla extends Car ) и «переопределяет» (принцип, который может быть знаком вам по C#) метод move , позволяя покрыть большее расстояние.

    Специальное ключевое слово super указывает на класс Car , от которого мы унаследовали — и раз уж мы упомянули C#, это сродни base . Смысл его существования в том, что чаще всего, когда мы переопределяем метод, заново реализуя его в наследуемом классе — класс Тесла в нашем примере — нам бывает нужно вызвать и метод базового класса. Таким образом нам не приходится заново копировать логику в наследуемый класс при каждом переопределении метода. Это было бы особенно паршиво, поскольку всякий раз при изменении базового класса нам бы пришлось переносить его логику в каждый наследуемый класс, превращая поддержку кода в сущий кошмар.

    Теперь, если вы проделаете следующее, то заметите, что автомобиль Tesla проезжает две дистанции в силу base.move() , как обычная машина, и еще четыре таких же дистанции сверх, потому что это вам не что-нибудь, а Tesla .

    Чаще всего приходится переопределять метод constructor . Здесь можно просто вызвать super() , передавая любые аргументы, нужные базовому классу. Автомобили Тесла в два раза быстрее, так что мы просто вызываем конструктор базового класса Car с удвоенной заявленной скоростью speed .

    Завтра мы перейдём к синтаксису let , const и for . of . Увидимся!

    Основы ES6 и полезные примеры по JavaScript для начинающих

    Основы ES6

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

    Получение определённых элементов из массива:

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

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

    Классы и объекты:

    Перебор значений (обход) массива:

    Задание параметров по умолчанию:

    Rest-параметры (получение большого количества параметров):

    Spread-оператор (оператора расширения) для преобразования массива в список аргументов для вывода или обработки значений массива:

    Spread-оператор для объединения нескольких массивов:

    Дополнительные полезные примеры

    Имитация приёма функцией — массива, имеющего значения по умолчанию:

    Присвоение элементов массива отдельным переменным:

    Замена if на switch:

    Ожидание выполнения нескольких асинхронных функций в конструкции async/await:

    Создание чистых объектов (абсолютно пустых):

    Форматирование JSON-кода:

    Удаление дублирующихся элементов массивов:

    Линеаризация многомерных массивов:

    Проверка наличия значения в нумерованном массиве:

    Получить новый массив, содержащий элементы удовлетворяющие заданному условию:

    Получить новый массив, содержащий элементы обработанные заданным условием:

    Вывод данных объекта

    • Object.values() — возвращает массив значений свойств переданного ему объекта.
    • Object.keys() — возвращает массив, состоящий из имён свойств объекта (ключей).
    • Object.entries() — возвращает массив, содержащий пары вида: [ключ, значение], представляющие собой имена свойств и значения этих свойств.

    Избранные определения из теории

    При копировании переменной с объектом – копируется эта ссылка (переменная), а объект по-прежнему остается в единственном экземпляре.

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

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

    Абстрагирование — это способ выделить набор значимых характеристик объекта, исключая из рассмотрения незначимые. Соответственно, абстракция — это набор всех таких характеристик.

    Полиморфизм — это свойство системы использовать объекты с одинаковым интерфейсом без информации о типе и внутренней структуре объекта.

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

    Итерируемые или, иными словами, «перебираемые» объекты — это те объекты, содержимое которых можно перебрать в цикле.

    Общие рекомендации

    • Используйте понятные имена переменных и функций.
    • Пишите короткие функции, решающие одну задачу.
    • Документируйте код.
    • Помните о принципе DRY — избегайте дублирования кода.

    Урок 10. ES6 (EcmaScript 6). Классы

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

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

    Классы в JavaScript? Что ты имеешь в виду?

    JavaScript — прототипно-ориентированный язык, что это еще за классы в ES6? Классы — синтаксический «сахар» поверх прототипного наследования — уловка, делающая язык притягательнее для программистов, пришедших из других парадигм, и, возможно, не совсем знакомых с цепочками прототипов. Многие фичи в ES6 (такие как деструктирование), по сути, синтаксический «сахар» — и классы не исключение. Я остановился на этом подробно, поскольку так нам будет легче понять базовую технологию, стоящую за классами в ES6. Саму структуру языка не переделывали, а просто упростили работу с прототипным наследованием для тех, кто привык к классам.

    Хотя мне и не нравится термин «классы» для этой конкретной фичи, я вынужден признаться, что в действительности работать с этим синтаксисом гораздо легче, чем с синтаксисом обычного прототипного наследования в ES5, и это выигрыш для каждого — как их ни называй.

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

    Чтобы запустить автомобиль, вы могли бы использовать следующий кусок кода.

    Отлично. А что на счёт классов в ES6? Синтаксис очень похож на объявление объекта, только здесь впереди подставляется class Name , где Name — название класса. Здесь мы используем нотацию сигнатуры метода, которую мы обсуждали вчера при объявлении методов с помощью сокращённого синтаксиса. constructor — такой же метод-конструктор, как в ES5, так что это можно использовать для инициализации любых переменных, которые могут быть у экземпляров.

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

    У классов зачастую есть статические методы. Возьмите, к примеру, нашего старого приятеля Array . У каждого экземпляра массива есть его «персональные» методы .filter , .reduce и .map . Но и у «класса» Array есть свои статические методы, например, Array.isArray . Добавить подобные методы к «классу» Car и в ES5 довольно просто:

    В нотации ES6, с class , мы можем вставить перед методом static , по той же логике синтаксиса, что у get и set . Опять же, лишь «сахар» для ES5, поскольку перевести это в синтаксис старой версии не составляет труда.

    Дополнительную сладость «сахарку» class в ES6 придает то, что в придачу к нему идет ключевое слово extends, дающее возможность легко «наследоваться» от других «классов». Мы знаем, что Тесла проезжает больше на том же количестве топлива, и в коде ниже видно, как класс Tesla расширяет класс Car ( Tesla extends Car ) и «переопределяет» (принцип, который может быть знаком вам по C#) метод move , позволяя покрыть большее расстояние.

    Специальное ключевое слово super указывает на класс Car , от которого мы унаследовали — и раз уж мы упомянули C#, это сродни base . Смысл его существования в том, что чаще всего, когда мы переопределяем метод, заново реализуя его в наследуемом классе — класс Тесла в нашем примере — нам бывает нужно вызвать и метод базового класса. Таким образом нам не приходится заново копировать логику в наследуемый класс при каждом переопределении метода. Это было бы особенно паршиво, поскольку всякий раз при изменении базового класса нам бы пришлось переносить его логику в каждый наследуемый класс, превращая поддержку кода в сущий кошмар.

    Теперь, если вы проделаете следующее, то заметите, что автомобиль Tesla проезжает две дистанции в силу base.move() , как обычная машина, и еще четыре таких же дистанции сверх, потому что это вам не что-нибудь, а Tesla .

    Чаще всего приходится переопределять метод constructor . Здесь можно просто вызвать super() , передавая любые аргументы, нужные базовому классу. Автомобили Тесла в два раза быстрее, так что мы просто вызываем конструктор базового класса Car с удвоенной заявленной скоростью speed .

    Завтра мы перейдём к синтаксису let , const и for . of . Увидимся!

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