Статьи

ECMAScript 6 Power Tutorial: класс и наследование

Я хотел бы поделиться с вами серией статей о ECMAScript 6, поделиться своей страстью к нему и объяснить, как он может работать для вас. Я надеюсь, что вам нравится читать их так же, как я их писал.

Во-первых, я работаю в Microsoft над механизмом рендеринга браузера для Microsoft Edge , который является значительным улучшением по сравнению с механизмом Internet Explorer, который мы узнали (и любим?) За эти годы. Моя личная любимая особенность в том, что он поддерживает ECMAScript 6. Для меня это огромное преимущество при написании больших приложений для Интернета.

Сейчас у нас почти 70% возможностей ECMAScript 6 в Microsoft Edge, согласно http://kangax.github.io/compat-table/es6/ и ES6 на dev.modern.ie/platform/status .

Таблица возможностей ECMAScript 6 в Microsoft Edge

Я люблю JavaScript, но когда дело доходит до работы над большими проектами, такими как Babylon.js, я предпочитаю TypeScript , который теперь поддерживает Angular 2 . Причина в том, что JavaScript (иначе известный как ECMAScript 5) не имеет всех функций синтаксиса, к которым я привык из других языков, в которых я пишу большие проекты. Например, я скучаю по классам и наследованию.

Так что без дальнейших церемоний, давайте углубимся в это:

JavaScript является прототипно-ориентированным языком, и с помощью ECMAScript 5 можно моделировать классы и наследование.

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
var Animal = (function () {
    function Animal(name) {
        this.name = name;
    }
    // Methods
    Animal.prototype.doSomething = function () {
        console.log(«I’m a » + this.name);
    };
    return Animal;
})();
 
 
var lion = new Animal(«Lion»);
lion.doSomething();

Здесь мы видим, что мы определили « класс » с « свойствами » и « методами ».

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

Это работает, но предполагает, что вы знаете о наследовании прототипов, и для кого-то, кто прибегает к языку на основе классов, это выглядит очень странно Как ни странно, в JavaScript есть ключевое слово class, но он ничего не делает. ECMAScript 6 теперь делает эту работу и позволяет использовать более короткий код:

01
02
03
04
05
06
07
08
09
10
11
12
class AnimalES6 {
    constructor(name) {
        this.name = name;
    }
 
    doSomething() {
        console.log(«I’m a » + this.name);
    }
}
 
var lionES6 = new AnimalES6(«Lion»);
lionES6.doSomething();

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

Кроме того, классы вводят ряд новых семантик, которых нет в эквиваленте ECMAScript 5. Например, вы не можете вызывать конструктор без new , и вы не можете пытаться создавать методы с new . Другое изменение заключается в том, что методы не перечисляются.

Интересный момент здесь: обе версии могут жить бок о бок.

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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class AnimalES6 {
    constructor(name) {
        this.name = name;
        this._age = 0;
    }
 
    get age() {
        return this._age;
    }
 
    set age(value) {
        if (value < 0) {
            console.log(«We do not support undead animals»);
        }
 
        this._age = value;
    }
 
    doSomething() {
        console.log(«I’m a » + this.name);
    }
}
 
var lionES6 = new AnimalES6(«Lion»);
lionES6.doSomething();
lionES6.age = 5;

Довольно удобно, правда?

Но мы можем видеть здесь общее предостережение о JavaScript: «не очень частный» закрытый член ( _age ). Я написал статью некоторое время назад на эту тему .

К счастью, теперь у нас есть лучший способ сделать это с помощью новой функции ECMAScript 6: символы.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var ageSymbol = Symbol();
 
class AnimalES6 {
    constructor(name) {
        this.name = name;
        this[ageSymbol] = 0;
    }
 
    get age() {
        return this[ageSymbol];
    }
 
    set age(value) {
        if (value < 0) {
            console.log(«We do not support undead animals»);
        }
 
        this[ageSymbol] = value;
    }
 
    doSomething() {
        console.log(«I’m a » + this.name);
    }
}
 
var lionES6 = new AnimalES6(«Lion»);
lionES6.doSomething();
lionES6.age = 5;

Так что же это за символ? Это уникальный и неизменный тип данных, который можно использовать в качестве идентификатора для свойств объекта. Если у вас нет символа, вы не можете получить доступ к собственности.

Это приводит к более «частному» доступу участника.

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

Но это еще не совсем приватно, потому что благодаря Object.getOwnPropertySymbols нижестоящие потребители могут получить доступ к вашим свойствам символов.

Когда у нас есть классы, мы также хотим иметь наследование. Еще раз — возможно моделировать наследование в ES5 , но это довольно сложно сделать.

Например, вот что производит TypeScript для имитации наследования:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
var __extends = this.__extends ||
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d;
    __.prototype = b.prototype;
    d.prototype = new __();
};
var SwitchBooleanAction = (function (_super) {
     __extends(SwitchBooleanAction, _super);
     function SwitchBooleanAction(triggerOptions, target, propertyPath, condition) {
        _super.call(this, triggerOptions, condition);
        this.propertyPath = propertyPath;
        this._target = target;
     }
     SwitchBooleanAction.prototype.execute = function () {
        this._target[this._property] = !this._target[this._property];
     };
     return SwitchBooleanAction;
})(BABYLON.Action);

Не очень легко читать.

Но альтернатива ECMAScript 6 лучше:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var legsCountSymbol = Symbol();
class InsectES6 extends AnimalES6 {
    constructor(name) {
        super(name);
        this[legsCountSymbol] = 0;
    }
 
    get legsCount() {
        return this[legsCountSymbol];
    }
 
    set legsCount(value) {
        if (value < 0) {
            console.log(«We do not support nether or interstellar insects»);
        }
 
        this[legsCountSymbol] = value;
    }
 
    doSomething() {
        super.doSomething();
        console.log(«And I have » + this[legsCountSymbol] + » legs!»);
    }
}
 
var spiderES6 = new InsectES6(«Spider»);
spiderES6.legsCount = 8;
spiderES6.doSomething();

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

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

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

Прежде всего, последняя версия TypeScript (1.4) начала добавлять поддержку кода ECMAScript 6 (с ключевыми словами let и const ), поэтому вам просто нужно сохранить существующий код TypeScript и включить эту новую опцию, чтобы начать генерировать код ECMAScript 6.

Но если вы внимательно посмотрите на некоторый TypeScript, вы обнаружите, что это похоже на ECMAScript 6 без типов. Поэтому изучение TypeScript сегодня — это отличный способ понять ECMAScript 6 завтра!

Используя TypeScript, теперь вы можете использовать все это в разных браузерах, поскольку ваш код преобразуется в ECMAScript 5. Если вы хотите использовать ECMAScript 6 непосредственно в браузере, вы можете выполнить обновление до Windows 10 и протестировать его с помощью механизма рендеринга Microsoft Edge.

Если вы не хотите делать это просто для того, чтобы опробовать некоторые новые функции браузера, вы также можете получить доступ к компьютеру Windows 10 с Microsoft Edge по адресу remote.modern.ie . Это также работает на вашем Mac OS или Linux.

Конечно, Microsoft Edge — не единственный браузер, поддерживающий открытый стандарт ES6. Другие браузеры также доступны, и вы можете отслеживать уровень поддержки по адресу: http://kangax.github.io/compat-table/es6/ .

Будущее JavaScript с ECMAScript 6 блестящее, и, честно говоря, я не могу дождаться, чтобы увидеть его широкую поддержку во всех современных браузерах!

Эта статья является частью серии технологий веб-разработки от Microsoft. Мы рады поделиться с вами Microsoft Edge и новым механизмом рендеринга EdgeHTML . Получите бесплатные виртуальные машины или проведите удаленное тестирование на устройстве Mac, iOS, Android или Windows @ http://dev.modern.ie/ .