Classes

Этот перевод не завершён. Пожалуйста, помогите перевести эту статью с английского

Классы в JavaScript были введены в ECMAScript 2015 и представляют собой синтаксический сахар над существующим в JavaScript механизмом прототипного наследования. Синтаксис классов не вводит новую объектно-ориентированную модель, а предоставляет более простой и понятный способ создания объектов и организации наследования.

Определение классов

На самом деле классы — это "специальные функции", поэтому точно также, как вы определяете функции (function expressions и function declarations), вы можете определять и классы с помощью: class declarations и class expressions.

Объявление класса

Первый способ определения класса — class declaration (объявление класса). Для этого необходимо воспользоваться ключевым словом class и указать имя класса (в примере — «Rectangle»).

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

Подъём (hoisting)

Разница между объявлением функции (function declaration) и объявлением класса (class declaration) в том, что объявление функции совершает подъём (hoisted), в то время как объявление класса — нет. Поэтому вначале необходимо объявить ваш класс и только затем работать с ним, а код же вроде следующего сгенерирует исключение типа ReferenceError:

var p = new Rectangle(); // ReferenceError

class Rectangle {}

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

Второй способ определения класса — class expression (выражение класса). Можно создавать именованные и безымянные выражения. В первом случае имя выражения класса находится в локальной области видимости класса и может быть получено через свойства самого класса, а не его экземпляра.

// безымянный
var Rectangle = class {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};
console.log(Rectagle.name);
// отобразится: "Rectangle" 

// именованный
var Rectangle = class Rectangle2 {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};  
console.log(Rectangle.name);
// отобразится: "Rectangle2" 

Обратите внимание: выражения класса подвержены тем же проблемам с подъёмом (hoisting), что и объявления класса.

Тело класса и задание методов

Тело класса — это часть кода, заключенная в фигурные скобки {}. Здесь вы можете объявлять члены класса, такие как методы и конструктор.

Строгий режим

Тела объявлений классов и выражений классов выполняются в строгом режиме (strict mode).

Constructor

Метод constructor — специальный метод, необходимый для создания и инициализации объектов, созданных, с помощью класса. В классе может быть только один метод с именем constructor. Исключение типа SyntaxError будет выброшено, если класс содержит более одного вхождения метода constructor.

Ключевое слово super можно использовать в методе constructor для вызова конструктора родительского класса.

Методы прототипа

См. также определение методов.

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
  
  get area() {
    return this.calcArea();
  }

  calcArea() {
    return this.height * this.width;
  }
}

const square = new Rectangle(10, 10);

console.log(square.area); // 100

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

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

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  static distance(a, b) {
    const dx = a.x - b.x;
    const dy = a.y - b.y;

    return Math.hypot(dx, dy);
  }
}

const p1 = new Point(5, 5);
const p2 = new Point(10, 10);

console.log(Point.distance(p1, p2));

Упаковка в прототипных и статических методах

Когда статический или прототипный метод вызывается без привязки к "this" объекта (или когда "this" является типом boolean, string, number, undefined, null), тогда "this" будет иметь значение "undefined" внутри вызываемой функции. Автоупаковка не будет произведена. Поведение будет таким же как если бы мы писали код в нестрогом режиме.

class Animal { 
  speak() {
    return this;
  }
  static eat() {
    return this;
  }
}

let obj = new Animal();
obj.speak(); // Animal {}
let speak = obj.speak;
speak(); // undefined

Animal.eat() // class Animal
let eat = Animal.eat;
eat(); // undefined

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

function Animal() { }

Animal.prototype.speak = function(){
  return this;
}

Animal.eat = function() {
  return this;
}

let obj = new Animal();
let speak = obj.speak;
speak(); // глобальный объект

let eat = Animal.eat;
eat(); // глобальный объект

Наследование классов с помощью extends

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

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(this.name + ' издает звук.');
  }
}

class Dog extends Animal {
  speak() {
    console.log(this.name + ' лает.');
  }
}

var d = new Dog('Митци');
d.speak();

Аналогичным образом можно расширять традиционные, основанные на функциях "классы":

function Animal (name) {
  this.name = name;  
}
Animal.prototype.speak = function () {
  console.log(this.name + ' издает звук.');
}

class Dog extends Animal {
  speak() {
    console.log(this.name + ' лает.');
  }
}

var d = new Dog('Митци');
d.speak();

Обратите внимание, что классы не могут расширять обычные (non-constructible) объекты. Если вам необходимо создать наследование от обычного объекта, в качестве замены можно использовать Object.setPrototypeOf():

var Animal = {
  speak() {
    console.log(this.name + ' издает звук.');
  }
};

class Dog {
  constructor(name) {
    this.name = name;
  }
  speak() {
    console.log(this.name + ' лает.');
  }
}
Object.setPrototypeOf(Dog.prototype, Animal);

var d = new Dog('Митци');
d.speak();

Species

Допустим, вам хотелось бы возвращать объекты типа Array в вашем производном от массива классе MyArray. Паттерн species позволяет вам переопределять конструкторы по умолчанию.

Например, при использовании таких методов, как map(), который возвращает конструктор по умолчанию, вам хотелось бы, чтобы они возвращали родительский объект Array вместо объекта MyArray. Символ Symbol.species позволяет это реализовать:

class MyArray extends Array {
  // Изменить species на родительский конструктор Array
  static get [Symbol.species]() { return Array; }
}
var a = new MyArray(1,2,3);
var mapped = a.map(x => x * x);

console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array);   // true

Обращение к родительскому классу с помощью super

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

class Cat { 
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    console.log(this.name + ' издает звук.');
  }
}

class Lion extends Cat {
  speak() {
    super.speak();
    console.log(this.name + ' рычит.');
  }
}

Mix-ins

Абстрактные подклассы, или mix-ins, — это шаблоны для классов. У класса в ECMAScript может быть только один родительский класс, поэтому множественное наследование (к примеру, от tooling classes) невозможно. Функциональность должен предоставлять родительский класс.

Для реализации mix-ins в ECMAScript можно использовать функцию, которая в качестве аргумента принимает родительский класс, а возвращает подкласс, его расширяющий:

var calculatorMixin = Base => class extends Base {
  calc() { }
};

var randomizerMixin = Base => class extends Base {
  randomize() { }
};

Класс, использующий такие mix-ins, можно описать следующим образом:

class Foo { }
class Bar extends calculatorMixin(randomizerMixin(Foo)) { }

Спецификации

Спецификация Статус Комментарий
ECMAScript 2015 (6th Edition, ECMA-262)
Определение 'Class definitions' в этой спецификации.
Стандарт Изначальное определение.
ECMAScript (ECMA-262)
Определение 'Class definitions' в этой спецификации.
Живой стандарт

Совместимость с браузерами

Update compatibility data on GitHub
КомпьютерыМобильныеServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome для AndroidFirefox для AndroidOpera для AndroidSafari on iOSSamsung InternetNode.js
classesChrome Полная поддержка 49
Полная поддержка 49
Нет поддержки 42 — 49
Замечания
Замечания Strict mode is required.
Нет поддержки 42 — 49
Отключено
Отключено From version 42 until version 49 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled). To change preferences in Chrome, visit chrome://flags.
Edge Полная поддержка 13Firefox Полная поддержка 45IE Нет поддержки НетOpera Полная поддержка 36
Полная поддержка 36
Нет поддержки 29 — 36
Замечания
Замечания Strict mode is required.
Нет поддержки 29 — 36
Отключено
Отключено From version 29 until version 36 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled).
Safari Полная поддержка 9WebView Android Полная поддержка 49
Полная поддержка 49
Нет поддержки 42 — 49
Замечания
Замечания Strict mode is required.
Chrome Android Полная поддержка 49
Полная поддержка 49
Нет поддержки 42 — 49
Замечания
Замечания Strict mode is required.
Нет поддержки 42 — 49
Отключено
Отключено From version 42 until version 49 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled). To change preferences in Chrome, visit chrome://flags.
Firefox Android Полная поддержка 45Opera Android Полная поддержка 36
Полная поддержка 36
Нет поддержки 29 — 36
Замечания
Замечания Strict mode is required.
Нет поддержки 29 — 36
Отключено
Отключено From version 29 until version 36 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled).
Safari iOS Полная поддержка 9Samsung Internet Android Полная поддержка 5.0
Полная поддержка 5.0
Нет поддержки 4.0 — 5.0
Замечания
Замечания Strict mode is required.
nodejs Полная поддержка 6.0.0
Полная поддержка 6.0.0
Полная поддержка 4.0.0
Отключено
Отключено From version 4.0.0: this feature is behind the --use_strict runtime flag.
Полная поддержка 5.0.0
Отключено
Отключено From version 5.0.0: this feature is behind the --harmony runtime flag.
constructorChrome Полная поддержка 49
Полная поддержка 49
Нет поддержки 42 — 49
Замечания
Замечания Strict mode is required.
Нет поддержки 42 — 49
Отключено
Отключено From version 42 until version 49 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled). To change preferences in Chrome, visit chrome://flags.
Edge Полная поддержка 13Firefox Полная поддержка 45IE Нет поддержки НетOpera Полная поддержка 36
Полная поддержка 36
Нет поддержки 29 — 36
Замечания
Замечания Strict mode is required.
Нет поддержки 29 — 36
Отключено
Отключено From version 29 until version 36 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled).
Safari Полная поддержка 9WebView Android Полная поддержка 49
Полная поддержка 49
Нет поддержки 42 — 49
Замечания
Замечания Strict mode is required.
Chrome Android Полная поддержка 49
Полная поддержка 49
Нет поддержки 42 — 49
Замечания
Замечания Strict mode is required.
Нет поддержки 42 — 49
Отключено
Отключено From version 42 until version 49 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled). To change preferences in Chrome, visit chrome://flags.
Firefox Android Полная поддержка 45Opera Android Полная поддержка 36
Полная поддержка 36
Нет поддержки 29 — 36
Замечания
Замечания Strict mode is required.
Нет поддержки 29 — 36
Отключено
Отключено From version 29 until version 36 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled).
Safari iOS Полная поддержка 9Samsung Internet Android Полная поддержка 5.0
Полная поддержка 5.0
Нет поддержки 4.0 — 5.0
Замечания
Замечания Strict mode is required.
nodejs Полная поддержка 6.0.0
Полная поддержка 6.0.0
Полная поддержка 4.0.0
Отключено
Отключено From version 4.0.0: this feature is behind the --use_strict runtime flag.
Полная поддержка 5.0.0
Отключено
Отключено From version 5.0.0: this feature is behind the --harmony runtime flag.
extendsChrome Полная поддержка 49
Полная поддержка 49
Нет поддержки 42 — 49
Замечания
Замечания Strict mode is required.
Нет поддержки 42 — 49
Отключено
Отключено From version 42 until version 49 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled). To change preferences in Chrome, visit chrome://flags.
Edge Полная поддержка 13Firefox Полная поддержка 45IE Нет поддержки НетOpera Полная поддержка 36
Полная поддержка 36
Нет поддержки 29 — 36
Замечания
Замечания Strict mode is required.
Нет поддержки 29 — 36
Отключено
Отключено From version 29 until version 36 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled).
Safari Полная поддержка 9WebView Android Полная поддержка 49
Полная поддержка 49
Нет поддержки 42 — 49
Замечания
Замечания Strict mode is required.
Chrome Android Полная поддержка 49
Полная поддержка 49
Нет поддержки 42 — 49
Замечания
Замечания Strict mode is required.
Нет поддержки 42 — 49
Отключено
Отключено From version 42 until version 49 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled). To change preferences in Chrome, visit chrome://flags.
Firefox Android Полная поддержка 45Opera Android Полная поддержка 36
Полная поддержка 36
Нет поддержки 29 — 36
Замечания
Замечания Strict mode is required.
Нет поддержки 29 — 36
Отключено
Отключено From version 29 until version 36 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled).
Safari iOS Полная поддержка 9Samsung Internet Android Полная поддержка 5.0
Полная поддержка 5.0
Нет поддержки 4.0 — 5.0
Замечания
Замечания Strict mode is required.
nodejs Полная поддержка 6.0.0
Полная поддержка 6.0.0
Полная поддержка 4.0.0
Отключено
Отключено From version 4.0.0: this feature is behind the --use_strict runtime flag.
Полная поддержка 5.0.0
Отключено
Отключено From version 5.0.0: this feature is behind the --harmony runtime flag.
Private class fieldsChrome Полная поддержка 74Edge Полная поддержка 79Firefox Нет поддержки НетIE Нет поддержки НетOpera Полная поддержка 62Safari Нет поддержки НетWebView Android Полная поддержка 74Chrome Android Полная поддержка 74Firefox Android Нет поддержки НетOpera Android Полная поддержка 53Safari iOS Нет поддержки НетSamsung Internet Android Нет поддержки Нетnodejs Полная поддержка 12.0.0
Public class fieldsChrome Полная поддержка 72Edge Полная поддержка 79Firefox Полная поддержка 69IE Нет поддержки НетOpera Полная поддержка 60Safari Нет поддержки НетWebView Android Полная поддержка 72Chrome Android Полная поддержка 72Firefox Android Нет поддержки НетOpera Android Полная поддержка 51Safari iOS Нет поддержки НетSamsung Internet Android Нет поддержки Нетnodejs Полная поддержка 12.0.0
staticChrome Полная поддержка 49
Полная поддержка 49
Нет поддержки 42 — 49
Замечания
Замечания Strict mode is required.
Нет поддержки 42 — 49
Отключено
Отключено From version 42 until version 49 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled). To change preferences in Chrome, visit chrome://flags.
Edge Полная поддержка 13Firefox Полная поддержка 45IE Нет поддержки НетOpera Полная поддержка 36
Полная поддержка 36
Нет поддержки 29 — 36
Замечания
Замечания Strict mode is required.
Нет поддержки 29 — 36
Отключено
Отключено From version 29 until version 36 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled).
Safari Полная поддержка 9WebView Android Полная поддержка 49
Полная поддержка 49
Нет поддержки 42 — 49
Замечания
Замечания Strict mode is required.
Chrome Android Полная поддержка 49
Полная поддержка 49
Нет поддержки 42 — 49
Замечания
Замечания Strict mode is required.
Нет поддержки 42 — 49
Отключено
Отключено From version 42 until version 49 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled). To change preferences in Chrome, visit chrome://flags.
Firefox Android Полная поддержка 45Opera Android Полная поддержка 36
Полная поддержка 36
Нет поддержки 29 — 36
Замечания
Замечания Strict mode is required.
Нет поддержки 29 — 36
Отключено
Отключено From version 29 until version 36 (exclusive): this feature is behind the Experimental JavaScript preference (needs to be set to Enabled).
Safari iOS Полная поддержка 9Samsung Internet Android Полная поддержка 5.0
Полная поддержка 5.0
Нет поддержки 4.0 — 5.0
Замечания
Замечания Strict mode is required.
nodejs Полная поддержка 6.0.0
Полная поддержка 6.0.0
Полная поддержка 4.0.0
Отключено
Отключено From version 4.0.0: this feature is behind the --use_strict runtime flag.
Полная поддержка 5.0.0
Отключено
Отключено From version 5.0.0: this feature is behind the --harmony runtime flag.
Static class fieldsChrome Полная поддержка 72Edge Полная поддержка 79Firefox Полная поддержка 75IE Нет поддержки НетOpera Полная поддержка 60Safari Нет поддержки НетWebView Android Полная поддержка 72Chrome Android Полная поддержка 72Firefox Android Нет поддержки НетOpera Android Полная поддержка 51Safari iOS Нет поддержки НетSamsung Internet Android Нет поддержки Нетnodejs Полная поддержка 12.0.0

Легенда

Полная поддержка  
Полная поддержка
Нет поддержки  
Нет поддержки
Смотрите замечания реализации.
Смотрите замечания реализации.
Пользователь должен сам включить эту возможность.
Пользователь должен сам включить эту возможность.

Смотрите также