Классы

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

Проверьте свое понимание

Что из следующего правильно определяет класс?

class MyClass {}
myClass = class {}
new class()

Сколько методов constructor() может иметь класс?

Один
Никто
Безлимитный