ES6 представил концепцию «классов» в JavaScript, которая отличается от классов в других языках программирования. Здесь классы — это специальные функции, которые служат шаблонами для создания объектов, уже содержащих данные, свойства, связанные с этими данными, и методы, связанные с манипулированием этими данными. Эти объекты, свойства и методы вместе называются «членами» класса.
Чтобы определить класс, используйте ключевое слово class
. Следуя передовому опыту и соглашению, установленному встроенными функциями-конструкторами JavaScript, любой идентификатор класса начинается с заглавной буквы:
class MyClass {}
Классы предназначены для предоставления более доступных способов работы с расширенными возможностями прототипов и функций конструктора:
class MyClass {}
typeof MyClass;
> "function"
Поскольку классы были частично добавлены для того, чтобы сделать работу с расширенными функциями JavaScript проще и привлекательнее, их иногда называют «синтаксическим сахаром» . Однако классы делают больше, чем просто предоставляют полезные сокращения для работы с прототипным наследованием . Введение синтаксиса классов создало возможности для решения давних проблем проектирования в JavaScript без возникновения проблем обратной совместимости. Например, весь код внутри тела класса всегда оценивается в строгом режиме .
Чтобы создать экземпляр класса, используйте new
оператор.
class MyClass {}
const myClassInstance = new MyClass();
myClassInstance;
> Object { }
Функции, определенные внутри тела класса, представляются как методы каждого экземпляра этого класса.
class MyClass {
classMethod() {
console.log( "My class method." );
}
}
const myClassInstance = new MyClass();
myClassInstance.classMethod();
> "My class method."
Метод, определенный внутри класса, становится методом прототипа результирующего экземпляра. Из-за особенностей цепочки прототипов вы можете вызывать эти методы непосредственно на результирующем объекте:
class MyClass {
classMethod() {
console.log( "My class method." );
}
}
const myClassInstance = new MyClass( "A string." );
myClassInstance;
> Object { }
<prototype>: Object { … }
classMethod: function classMethod()
constructor: class MyClass { constructor(myPassedValue) }
<prototype>: Object { … }
myClassInstance.classMethod();
> "My class method."
Создание экземпляра класса вызывает специальный constructor()
, который выполняет всю необходимую «настройку» вновь созданного экземпляра и инициализирует все связанные с ним свойства. Любые аргументы, передаваемые классу при создании экземпляра, доступны методу constructor()
:
class MyClass {
constructor( myPassedValue ) {
console.log( myPassedValue );
}
}
const myClassInstance = new MyClass( "A string." );
> "A string."
Внутри тела класса значение this
относится к самому экземпляру, при этом любые свойства, определенные в this
представляются как свойства каждого экземпляра этого класса:
class MyClass {
constructor( myPassedValue ) {
this.instanceProperty = myPassedValue;
}
}
const myClassInstance = new MyClass( "A string." );
myClassInstance;
> Object { instanceProperty: "A string." }
Эти свойства также доступны всем методам в теле класса:
class MyClass {
constructor( myPassedValue ) {
this.instanceProp = myPassedValue;
}
myMethod() {
console.log( this.instanceProp );
}
}
const myClassInstance = new MyClass( "A string." );
myClassInstance.myMethod();
> "A string."
Если вы не определяете constructor()
для своего класса, движок JavaScript предполагает пустой constructor
«по умолчанию». Каждый класс может иметь только один специальный метод с именем constructor()
:
class MyClass {
constructor() {}
constructor() {}
}
> Uncaught SyntaxError: A class may only have one constructor
Вы можете определить класс, используя либо объявление класса , либо выражение класса . Все предыдущие примеры представляли собой объявления классов, которые требуют вызова имен с использованием new
. Выражениям класса можно дать имя или оставить его без имени, чтобы создать «анонимный» класс.
let ClassExpression = class {
constructor() {}
};
ClassExpression;
> class {}
Единственное, для чего вы можете использовать выражения анонимного класса, — это функции, которые создают классы «на лету»:
function classMaker() {
return class {
constructor() {}
};
}
let MyVariable = classMaker();
MyVariable;
> class {}
Повторное объявление класса с использованием объявления класса приводит к синтаксической ошибке:
class MyClass {
constructor( ) {
console.log( "My class." );
}
};
class MyClass {
constructor() {
console.log( "My new class." );
}
};
> Uncaught SyntaxError: redeclaration of class MyClass
Однако выражения класса позволяют переопределить класс:
let ClassExpression = class MyClass { };
ClassExpression = class MyOtherClass {
constructor( myString ) {
this.myProp = myString;
}
};
new ClassExpression( "String." );
> MyOtherClass {myProp: 'String.'}
Вы не можете вызвать выражение именованного класса по имени так, как вы можете вызвать объявление класса. Однако назначенное имя выражения класса доступно как свойство созданного экземпляра, главным образом для облегчения отладки:
let MyVariable = class MyClass {};
MyClass;
> Uncaught ReferenceError: MyClass is not defined
MyVariable;
> class MyClass {}
MyVariable.name;
> "MyClass"
Когда вы инициализируете переменную с помощью выражения класса, правила подъема этой переменной соблюдаются, как и ожидалось. Объявления классов следуют тем же правилам «временной мертвой зоны», что и let
и const
, и ведут себя так, как будто они не были подняты на вершину своей текущей области действия, а это означает, что вызов класса до объявления класса вызывает ошибку:
{
let myVar = new MyClass( "Property string." );
class MyClass {
myProp;
constructor( myString ) {
this.myProp = myString;
}
};
};
> Uncaught ReferenceError: Cannot access 'MyClass' before initialization
Проверьте свое понимание
Что из следующего правильно определяет класс?
new class()
myClass = class {}
class MyClass {}
Сколько методов constructor()
может иметь класс?