Классы в js: Класс: базовый синтаксис

Содержание

Классы | JavaScript Camp

В JavaScript используется модель прототипного наследования: каждый объект наследует поля (свойства) и методы объекта-прототипа.

class​

Для определения класса используется ключевое🗝️ слово class:

class MyClass {
// методы класса
constructor() { ... }
method1() { ... }
method2() { ... }
method3() { ... }
...
}

Такой синтаксис📖 называется объявлением🗣️ класса.

Методы в классе не разделяются запятой

Синтаксис📖 классов отличается от литералов объектов. Внутри классов запятые не требуются.

Класс может не иметь названия. С помощью выражения класса можно присвоить класс переменной 🔔 :

const UserClass = class {
// тело класса
}

Классы можно экспортировать в виде модулей. Вот пример экспорта по умолчанию:

export default class User {
// тело класса
}

А вот пример именованного экспорта:

export class User {
// тело класса
}

Класс становится полезным, когда вы создаете экземпляр класса. Экземпляр — это объект, содержащий данные и поведение, описанные 🖊️ классом.

Оператор new создает🏗️ экземпляр класса в JavaScript таким образом: instance = new Class().

Например, вы можете создать🏗️ экземпляр класса User 👤 с помощью оператора new:

const myUser = new User()

new User() создает🏗️ экземпляр класса

User 👤.

Видео​

Инициализация: constructor()​

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

В следующем примере конструктор устанавливает начальное значение поля name:

class User {
constructor(name) {
this.name = name
}
}

constructor класса User использует один параметр name, который используется для установки начального значения поля this. name.

Внутри конструктора значение this равно вновь созданному🏗️ экземпляру.

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

function learnJavaScript() { class User { constructor(name) { name // => ‘Jon Snow’ this.name = name } } const user = new User(‘Jon Snow’) //Здесь можно менять значение return user.name }

Loading…

Параметр name внутри конструктора имеет значение Jon Snow.

Если вы не определяете конструктор для класса, создается🏗️ конструктор по умолчанию. Конструктор по умолчанию является пустой функцией⚙️, которая не изменяет экземпляр.

В классе может быть только один метод с именем constructor.

Отказ от классов​

Так как в курсе нашей школы мы учим разрабатывать мобильные приложения с помощью библиотеки React, где нововведение React Hooks позволяет использовать состояние и другие возможности React без написания классов. Поэтому рассказывать о классах больше нет смысла, так как мы от них отказались.

Проблемы?​

Пишите в Discord или телеграмм чат, а также подписывайтесь на наши новости

Вопросы:​

Какое ключевое🗝️ слово для определения класса?

  1. constructor()
  2. class
  3. this

Методы внутри класса разделяются ли запятой.

  1. true
  2. false

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

  1. Неограниченно
  2. До десяти
  3. Только один

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

Ссылки:​

  1. MDN web docs
  2. Learn JavaScript

Contributors ✨​

Thanks goes to these wonderful people (emoji key):


Philipp Dvinyaninov
📖

Dmitriy Vasilev
💵

Resoner2005
🐛 🎨 🖋

Navernoss
🖋 🐛 🎨

Классы | Карманная книга по TypeScript

  • Члены класса (class members)
    • Поля
    • Конструкторы
    • Методы
  • Классы и наследование
    • implements
    • extends
  • Видимость членов (member visibility)
    • public
    • protected
    • private
  • Статические члены
    • Специальные названия статических членов
  • Общие классы
    • Параметр типа в статических членах
  • Значение this в классах во время выполнения кода
    • Стрелочные функции
    • Параметры this
    • Типы this
  • Свойства параметров
  • Выражения классов (class expressions)
  • Абстрактные классы и члены
    • Сигнатуры абстрактных конструкций (abstract construct signatures)
  • Отношения между классами

Члены класса (class members)#

Вот пример самого простого класса — пустого:

Такой класс бесполезен, поэтому давайте добавим ему несколько членов.

Поля#

Поле — это открытое (публичное) и доступное для записи свойство класса:

Аннотация типа является опциональной (необязательной), но неявный тип будет иметь значение any.

Поля могут иметь инициализаторы, которые автоматически запускаются при инстанцировании класса:

Как и в случае с const, let и var, инициализатор свойства класса используется для предположения типа этого свойства:

--strictPropertyInitialization#

Настройка strictPropertyInitialization определяет, должны ли поля класса инициализироваться в конструкторе.

Обратите внимание

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

Если вы намерены инициализировать поле вне конструктора, можете использовать оператор утверждения определения присвоения (definite assignment assertion operator, !):

readonly#

Перед названием поля можно указать модификатор readonly. Это запретит присваивать полю значения за пределами конструктора.

Конструкторы#

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

Однако, между сигнатурами конструктора класса и функции существует несколько отличий:

  • Конструкторы не могут иметь параметров типа — это задача возлагается на внешнее определение класса, о чем мы поговорим позже
  • Конструкторы не могут иметь аннотацию возвращаемого типа — всегда возвращается тип экземпляра класса
super#

Как и в JS, при наличии базового класса в теле конструктора, перед использованием this необходимо вызывать super():

В JS легко забыть о необходимости вызова super, в TS — почти невозможно.

Методы#

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

Как видите, TS не добавляет к методам ничего нового.

Обратите внимание

В теле метода к полям и другим методам по-прежнему следует обращаться через this. Неквалифицированное название (unqualified name) в теле функции всегда будет указывать на лексическое окружение.

Геттеры/сеттеры#

Классы могут иметь акцессоры (вычисляемые свойства, accessors):

TS имеет несколько специальных правил, касающихся предположения типов в случае с акцессорами:

  • Если set отсутствует, свойство автоматически становится readonly
  • Параметр типа сеттера предполагается на основе типа, возвращаемого геттером
  • Если параметр сеттера имеет аннотацию типа, она должна совпадать с типом, возвращаемым геттером
  • Геттеры и сеттеры должны иметь одинаковую видимость членов (см. ниже)

Если есть геттер, но нет сеттера, свойство автоматически становится readonly.

Сигнатуры индекса (index signatures)#

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

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

Классы и наследование#

Как и в других объектно-ориентированных языках, классы в JS могут наследовать членов других классов.

implements#

implements используется для проверки соответствия класса определенному interface. При несоответствии класса интерфейсу возникает ошибка:

Классы могут реализовывать несколько интерейсов одновременно, например, class C implements A, B {}.

Предостережение#

Важно понимать, что implements всего лишь проверяет, соответствует ли класс определенному интерфейсу. Он не изменяет тип класса или его методов. Ошибочно полагать, что implements изменяет тип класса — это не так!

В приведенном примере мы, возможно, ожидали, что тип s будет определен на основе name: string в check. Это не так — implements не меняет того, как проверяется тело класса или предполагаются его типы.

Также следует помнить о том, что определение в интерфейсе опционального свойства не приводит к созданию такого свойства:

extends#

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

Перезапись методов#

Производный класс может перезаписывать свойства и методы базового класса. Для доступа к методам базового класса можно использовать синтаксис super. Поскольку классы в JS — это всего лишь объекты для поиска (lookup objects), такого понятия как «супер-поле» не существует.

TS обеспечивает, чтобы производный класс всегда был подтипом базового класса.

Пример «легального» способа перезаписи метода:

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

Что если производный класс не будет следовать конракту базового класса?

Если мы скомпилируем этот код, несмотря на ошибку, такой «сниппет» провалится:

Порядок инициализации#

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

Что здесь происходит?

Порядок инициализации согласно спецификации следующий:

  • Инициализация полей базового класса
  • Запуск конструктора базового класса
  • Инициализация полей производного класса
  • Запуск конструктора производного класса

Это означает, что конструктор базового класса использует собственное значение name, поскольку поля производного класса в этот момент еще не инициализированы.

Наследование встроенных типов#

В ES2015 конструкторы, неявно возвращающие объекты, заменяют значение this для любого вызова super. Для генерируемого конструктора важно перехватывать потенциальное значение, возвращаемое super, и заменять его значением this.

Поэтому подклассы Error, Array и др. могут работать не так, как ожидается. Это объясняется тем, что Error, Array и др. используют new. target из ES6 для определения цепочки прототипов; определить значение new.target в ES5 невозможно. Другие компиляторы, обычно, имеют такие же ограничения.

Для такого подкласса:

вы можете обнаружить, что:

  • методы объектов, возвращаемых при создании подклассов, могут иметь значение undefined, поэтому вызов sayHello завершится ошибкой
  • instanceof сломается между экземплярами подкласса и их экземплярами, поэтому (new MsgError()) instanceof MsgError возвращает false

Для решения данной проблемы можно явно устанавливать прототип сразу после вызова super.

Тем не менее, любой подкласс MsgError также должен будет вручную устанавливать прототип. В среде выполнения, в которой не поддерживается Object.setPrototypeOf, можно использовать __proto__.

Видимость членов (member visibility)#

Мы можем использовать TS для определения видимости методов и свойств для внешнего кода, т. е. кода, находящегося за пределами класса.

public#

По умолчанию видимость членов класса имеет значение public. Публичный член доступен везде:

Поскольку public является дефолтным значением, специально указывать его не обязательно, но это повышает читаемость и улучшает стиль кода.

protected#

Защищенные члены видимы только для подклассов класса, в котором они определены.

Раскрытие защищенных членов#

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

Обратите внимание

В производной классе для сохранения «защищенности» члена необходимо повторно указывать модификатор protected.

Доступ к защищенным членам за пределами иерархии классов#

Разные языки ООП по-разному подходят к доступу к защищенным членам из базового класса:

Java, например, считает такой подход легальным, а C# и C++ нет.

TS считает такой подход нелегальным, поскольку доступ к x из Derived2 должен быть легальным только в подклассах Derived2, а Derived1 не является одним из них.

private#

Частные члены похожи на защищенные, но не доступны даже в подклассах, т.е. они доступны только в том классе, где они определены.

Поскольку частные члены невидимы для производных классов, производный класс не может изменять их видимость:

Доступ к защищенным членам между экземплярами#

Разные языки ООП также по-разному подходят к предоставлению доступа экземплярам одного класса к защищенным членам друг друга. Такие языки как Java, C#, C++, Swift и PHP разрешают такой доступ, а Ruby нет.

TS разрешает такой доступ:

Предостережение#

Подобно другим аспектам системы типов TS, private и protected оказывают влияние на код только во время проверки типов. Это означает, что конструкции вроде in или простой перебор свойств имеют доступ к частным и защищенным членам:

Для реализации «настоящих» частных членов можно использовать такие механизмы, как замыкания (closures), слабые карты (weak maps) или синтаксис приватных полей класса (private fields, #).

Статические члены#

В классах могут определеяться статические члены. Такие члены не связаны с конкретными экземплярами класса. Они доступны через объект конструктора класса:

К статическим членам также могут применяться модификаторы public, protected и private:

Статические члены наследуются:

Специальные названия статических членов#

Изменение прототипа Function считается плохой практикой. Поскольку классы — это функции, вызываемые с помощью new, некоторые слова нельзя использовать в качестве названий статических членов. К таким словам относятся, в частности, свойства функций name, length и call:

Почему не существует статических классов?#

В некоторых языках, таких как C# или Java существует такая конструкция, как статический класс (static class).

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

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

Общие классы#

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

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

Параметр типа в статических членах#

Следующий код, как ни странно, является НЕлегальным:

Запомните, что типы полностью удаляются! Во время выполнения существует только один слот Box.defaultValue. Это означает, что установка Box<string>.defaultValue (если бы это было возможным) изменила бы Box<number>. defaultValue, что не есть хорошо. Поэтому статические члены общих классов не могут ссылаться на параметры типа класса.

Значение

this в классах во время выполнения кода#

TS не изменяет поведения JS во время выполнения. Обработка this в JS может показаться необычной:

Если кратко, то значение this внутри функции зависит от того, как эта функция вызывается. В приведенном примере, поскольку функция вызывается через ссылку на obj, значением this является obj, а не экземпляр класса.

TS предоставляет некоторые средства для изменения такого поведения.

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

Если у вас имеется функция, которая часто будет вызываться способом, приводящим к потере контекста, имеет смысл определить такое свойство в виде стрелочной функции:

Это требует некоторых компромиссов:

  • Значение this будет гарантированно правильным во время выполнения, даже в коде, не прошедшем проверки с помощью TS
  • Будет использоваться больше памяти, поскольку для каждого экземпляра класса будет создаваться новая функция
  • В производном классе нельзя будет использовать super. getName, поскольку отсутствует входная точка для получения метода базового класса в цепочке прототипов

Параметры

this#

При определении метода или функции начальный параметр под названием this имеет особое значение в TS. Данный параметр удаляется во время компиляции:

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

Данный подход также сопряжен с несколькими органичениями:

  • Мы все еще имеем возможность вызывать метод неправильно
  • Выделяется только одна функция для каждого определения класса, а не для каждого экземпляра класса
  • Базовые определения методов могут по-прежнему вызываться через super

Типы

this#

В классах специальный тип this динамически ссылается на тип текущего класса:

Здесь TS предполагает, что типом this является тип, возвращаемый set, а не Box. Создадим подкласс Box:

Мы также можем использовать this в аннотации типа параметра:

Это отличается от other: Box — если у нас имеется производный класс, его метод sameAs будет принимать только другие экземпляры этого производного класса:

Основанные на
this защитники типа#

Мы можем использовать this is Type в качестве возвращаемого типа в методах классов и интерфейсах. В сочетании с сужением типов (например, с помощью инструкции if), тип целевого объекта может быть сведен к более конкретному Type.

Распространенным случаем использования защитников или предохранителей типа (type guards) на основе this является «ленивая» валидация определенного поля. В следующем примере мы удаляем undefined из значения, содержащегося в box, когда hasValue проверяется на истинность:

Свойства параметров#

TS предоставляет специальный синтаксис для преобразования параметров конструктора в свойства класса с аналогичными названиями и значениями. Это называется свойствами параметров (или параметризованными свойствами), такие свойства создаются с помощью добавления модификаторов public, private, protected или readonly к аргументам конструктора. Создаваемые поля получают те же модификаторы:

Выражения классов (class expressions)#

Выражения классов похожи на определения классов. Единственным отличием между ними является то, что выражения классов не нуждаются в названии, мы можем ссылаться на них с помощью любого идентификатора, к которому они привязаны (bound):

Абстрактные классы и члены#

Классы, методы и поля в TS могут быть абстрактными.

Абстрактным называется метод или поле, которые не имеют реализации. Такие методы и поля должны находится внутри абстрактного класса, который не может инстанцироваться напрямую.

Абстрактные классы выступают в роли базовых классов для подклассов, которые реализуют абстрактных членов. При отсутствии абстрактных членов класс считается конкретным (concrete).

Рассмотрим пример:

Мы не можем инстанцировать Base с помощью new, поскольку он является абстрактным. Вместо этого, мы должны создать производный класс и реализовать всех абстрактных членов:

Обратите внимание

Если мы забудем реализовать абстрактных членов, то получим ошибку.

Сигнатуры абстрактных конструкций (abstract construct signatures)#

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

Рассмотрим пример:

TS сообщает нам о том, что мы пытаемся создать экземпляр абстрактного класса. Тем не менее, имея определение greet, мы вполне можем создать абстрактный класс:

Вместо этого, мы можем написать функцию, которая принимает нечто с сигнатурой конструктора:

Теперь TS правильно указывает нам на то, какой конструктор может быть вызван — Derived может, а Base нет.

Отношения между классами#

В большинстве случаев классы в TS сравниваются структурно, подобно другим типам.

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

Также существуют отношения между подтипами, даже при отсутствии явного наследования:

Однако, существует одно исключение.

Пустые классы не имеют членов. В структурном отношении такие классы являются «супертипами» для любых других типов. Так что, если мы создадим пустой класс (не надо этого делать!), вместо него можно будет использовать что угодно:

JS: Классы по JavaScript. Введение | Кудзанайи Дзвайро

Введение

Мы узнали, что JavaScript — это язык, основанный на прототипах, и каждый объект в JavaScript имеет скрытое внутреннее свойство, называемое [[Prototype]], которое можно использовать для расширения свойств и методов объекта.

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

Классы — это функции

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

 //Инициализация функции выражением функции 
const x = function () {}//Инициализация класса выражением класса
const y = class {}

Ранее мы узнали, что можем получить доступ к [[Prototype ]] объекта с помощью метода Object.getPrototypeOf(). Теперь давайте проверим это на пустой функции, которую мы создали

 Object.getPrototypeOf(x)//f () { [собственный код] } 

Теперь мы можем проверить то же самое на только что созданном классе.

 Object.getPrototypeOf(y)//f () { [собственный код] } 

Мы видим, что код, объявленный с помощью функции и класса, возвращает [[Prototype]]. С помощью прототипов мы узнали, что любая функция может стать экземпляром конструктора, используя ключевое слово new.

 const x = function() {}//Инициализировать конструктор из функции 
const конструкторFromFunction = new x()console.log(constructorFromFunction)//x{}
конструктор: f()

Это относится и к классам

 const y = class {}//Инициализация конструктора из класса 
conststructorFromClass = new y()console.log(constructorFromClass)//y{}
конструктор: класс

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

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

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

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

 //Инициализация функции-конструктора 
function Hero(name, level){
this.name = name
this.name = level
}
}

Новый синтаксис класса имеет аналогичную структуру

 class Hero { 
конструктор (имя, уровень){
this.name = name
this.level = level
}
}

Мы знаем, что функция-конструктор предназначена для создания чертежа объекта, по капитализации первой буквы инициализатора (что необязательно) и по знакомству с синтаксисом . Ключевое слово class более прямо передает цель нашей функции.

Единственная разница в синтаксисе инициализации заключается в использовании ключевого слова класса вместо функции и присвоении свойств внутри метода конструктора(). Ключевое слово class более прямо передает цель нашей функции

Определение методов

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

 function Hero(name, level){ 
this.name = name
this.level = level
}//Добавление метода в конструктор
Hero.prototype.greet = function() {
return `${this. имя} говорит привет.`
}

С классами этот синтаксис упрощается, и метод может быть добавлен непосредственно в класс. Используя сокращенное определение метода, введенное в ES6, определение метода является еще более кратким процессом.

 class Hero{ 
конструктор(имя, уровень) {
this.name = имя
this.level = уровень
} приветствие(){
return `${this.name} говорит привет.`
}
}

Давайте посмотрим на эти свойства и методы в действии. Мы создадим новый экземпляр Hero, используя новое ключевое слово, и назначим некоторые значения

 const1 hero1 = new Hero('Varg', 1) 

Если мы выведем дополнительную информацию о нашем новом объекте с помощью console.log(hero1), мы можем увидеть более подробную информацию о том, что происходит с инициализацией класса.

 Герой {имя: "Варг", уровень: 1} 
__proto__:
▶ конструктор: класс Герой
▶ приветствие: ƒ приветствие()

В выводе мы видим, что функции конструктора() и приветствия() были применяется к __proto__ или [[Prototype]] героя1, а не непосредственно как метод объекта hero1. Хотя это очевидно при создании функций-конструкторов, это не очевидно при создании классов. Классы допускают более простой и лаконичный синтаксис, но при этом жертвуют некоторой ясностью процесса.

Расширение класса

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

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

 //создать новый конструктор из родителя 
function Mage(имя, уровень, заклинание){
//Конструктор цепочки с вызовом
Hero. call(this, name, level)

this.spell = заклинание
}//Создание нового объекта с использованием прототипа Героя в качестве прототипа для только что созданный объект.
Mage.prototype = Object.create(Hero.prototype)

Теперь мы можем создать новый экземпляр Mage, используя те же свойства, что и Hero, а также новый, который мы добавили

 const hero2 = new Mage('Lejon' , 2, 'Волшебная стрела')//Маг {имя: "Леджон", уровень: 2, заклинание: "Волшебная стрела"} 
__proto__:
▶ конструктор: ƒ Маг(имя, уровень, заклинание)

В классах ES6 ключевое слово super используется вместо вызова для доступа к родительским функциям. Мы будем использовать расширения для ссылки на родительский класс.

 /создание нового класса из родительского класса 
Mage extends Herp {
конструктор(имя, уровень, заклинание){
//Конструктор цепи с супер
супер(имя, уровень) //добавляем новое свойство
this.spell = заклинание
}
}

Использование классов в JavaScript: 3 ошибки, которые вы, скорее всего, сделаете, и как их избежать | Адриан АБАБЕЙ

С 2015 года вопрос: «Почему в JavaScript нет классов?» , который раньше был на устах у любого разработчика, уже не актуален. Классы появились в ECMAScript 2015 (ES6). И еще: многие разработчики до сих пор не знают, как они работают. Более того, они не воспринимают классы JS как «настоящие» классы. Вот почему при использовании классов в JavaScript они допускают непреднамеренные ошибки, которые приводят к незаметным ошибкам в их приложениях.

  • «Но какие ошибки чаще всего возникают при неправильном обращении с классами JavaScript?»
  • «И как я могу избежать их или, по крайней мере, быстро исправить?»

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

Итак, вот 3 наиболее распространенные ошибки, которые вы тоже можете совершить при работе с классами в JavaScript:

Подробнее о классах JavaScript: действительно ли они «настоящие» классы?0138

Вот простое, но достаточно ясное определение классов в JavaScript:

По сути, это синтаксический сахар над прототипами (наследование на основе прототипов в JS) с гораздо более простым и понятным синтаксисом.

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

«Но являются ли классы JavaScript «настоящими» классами?» — еще один вопрос, «мучающий» многих JS-программистов.

Итак, позвольте мне пролить свет на эту «дилемму»:

Есть 2 незначительных различия между классами JS (или объектами, подобными классам JS) и так называемыми «настоящими» классы:

  1. при использовании классов в JavaScript вам необходимо добавить статические атрибуты после того, как вы определили свои классы
  2. также, нет частных членов

Кроме того, они служат той же практической цели и ведут себя как любая другая классовая система.

Кроме того, я хочу подчеркнуть тот факт, что классы JavaScript НЕ НЕ привносят какую-либо новую объектно-ориентированную модель наследования.

 

Ошибка № 1. Невыполнение кода JavaScript в «строгом режиме»

Проблемы со строгим режимом неизбежно приведут к ошибкам в вашем приложении.

Но вы, должно быть, прямо сейчас спрашиваете себя: «В чем смысл? Почему код JavaScript (имеется в виду тело класса — этот раздел в фигурных скобках) выполняется в строгом режиме?»

  1. потому что строгий режим «вызов» классам выдает некоторые из когда-то тихих ошибок
  2. потому что он запускает код в более строгом синтаксисе и, таким образом, устраняет некоторые из старых несоответствий в JavaScript
  3. 9

    «Когда возникают ошибки, точнее?»

    Если вы забыли выполнить свой код JavaScript — метод конструктора, метод прототипа, статический метод и другие функции — в строгом режиме!

    Примечание: еще один способ определить классы JavaScript — использовать выражения класса, которые могут быть как именованными, так и безымянными. Однако имейте в виду, что дублирование имени параметра не будет «разрешено» из-за строгого режима. Это автоматически приведет к… ошибкам.

     

    Ошибка № 2: неправильная обработка подклассов

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

    Как правильно это сделать?

    Использование ключевого слова «extends» в «выражении класса» или в «объявлении класса». Его роль заключается в создании таксономий классов с одним предком .

    Примечание: если у вас есть метод-конструктор в вашем дочернем классе, правильный способ сделать это — сначала вызвать « super()» , а затем ключевое слово « this ».

    Предупреждение: помните, что классы JavaScript не расширяют неконструируемые объекты. В этом случае вы можете использовать метод Object.setPrototypeOf() для безопасного наследования от обычного объекта!

     

    Ошибка № 3: Не объявлять классы JS перед их использованием

    … что приводит к проблемам с подъемом.

    Прежде всего, давайте попробуем определить «подъем»:

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

    Достаточно ясно?

    Кроме того, подъем — это та характеристика JS, которая устанавливает объявления функций (а классы JS воспринимаются как «специальные функции») кроме объявлений класса : последние не поднимаются.

    Итак, как предотвратить возникновение проблем с подъемом при использовании классов в JavaScript?

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

Оставить комментарий

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *