Классы в JavaScript OTUS
JavaScript – удобный и очень популярный язык программирования. Он ориентирован преимущественно на веб-разработку. Базируется на создании программного обеспечения с использованием сценариев (скриптов).
Среди пользователей, которые только начинают погружение в создание софта, является достаточно распространенным языком. Java Script выделяется простым и понятным синтаксисом, высокой читаемостью исходного кода, функциональностью.
Для того, чтобы можно было создавать качественное ПО на JS, нужно изучить некоторые ключевые функции и возможности ЯП. Пример – классы и его элементы. В данной статье речь зайдет именно о них.
Что это
В JS классы несколько отличаются от «общепринятых» понятий в объектно-ориентированном программировании. Здесь реализация соответствующих элементов отсутствует.
Класс в JavaScript:
- абстракция;
- надстройка над прототипным наследованием, которая имитирует класс;
- функция.
С ES2015 работать с соответствующими компонентами в JS стало намного проще, так как он добавил специальное ключевое слово, отвечающее за вызов интересующей функции. Речь идет о синтаксическом сахаре над прототипным наследованием.
Определение в коде
Добавить класс в программный код позволяет специальное ключевое слово. Речь идет о «class» (без кавычек). Оно добавляет новый класс. После ключевого слова необходимо задать имя соответствующего элемента кода. Далее – открыть фигурные скобки. Они отвечают за определение тела класса.
Указывать название класса не обязательно. Через его выражение можно назначить рассматриваемых элемент переменной или провести экспорт в качестве части модуля ES2015.
Класс становится полезным тогда, когда программист создает экземпляр класса. Это – объект, содержащий информацию и поведение, описанные при помощи соответствующих classes. Для создания экземпляра класса нужно использовать оператор new.
Инициализация
При инициализации экземпляра класса будет срабатывать специальная функция. Она носит название «constructor». Ее добавление происходит непосредственно в классе. Это – специальный метод, отвечающий за инициализацию classes. Тут можно устанавливать изначальные значения для полей, а также выполнять любые настройки элементов (объектов).
Здесь:
- Функция-конструктор принимает аргумент name.
- Name используется для определения свойства name в классе.
- Аргумент необходимо передать при создании экземпляра класса:
- Внутри конструктора происходит ссылка на новый экземпляр.
Если конструктор в рассматриваемом элементе кода не описывается, функция constructor все равно будет создана. Она окажется пустой.
Поля
Добавить в код класс – не самая трудная задача для программиста в JS. Это базовый навык, который должен освоить каждый. Из-за того, что экземпляр class в JS – это объект, то у него есть свойства. Они носят название полей.
В рассматриваемом элементе кода можно увидеть несколько типов полей:
- экземпляра;
- самого класса.
Каждый из них бывает публичным и приватным. Первый доступен в пределах всего исходного кода, второй – внутри class, в котором он определен.
Приватные поля
Доступ к публичным полям экземпляра предоставляется в теле класса. Чтобы добавить «приватность», нужно перед именем поля поставить символ «решетка» (#):
Тут приватное поле – name. У метода getName в теле рассматриваемого элемента есть доступ к нему. А вот напрямую воспользоваться им не получится.
Если пользователю необходимо задать статичное приватное поле (которое относится к самому class), сделать это можно при помощи ранее предложенного примера:
Публичные поля
Это – самый распространенный элемент кода. Доступ к нему предоставляется по всему исходному коду:
Комментарии тут можно дать следующие:
- Name – это публичное поле экземпляра.
- Для того, чтобы было удобнее работать с рассматриваемым элементом, можно декларировать поля не в конструкторе, а в теле classes.
- Декларация в теле особо удобна, если нужно присвоить свойствам дефолтные значения. Это ситуация, при которой передача аргументов в конструктор не является обязательной.
Статичные поля (classes) – свойства, принадлежащие самому классу. Данный момент удобен, если нужно сохранять константы или информацию, актуальную для всех без исключения элементов class.
Здесь публичных переменных две – TYPE_ADMIN и TYPE_REGULAR. Так как строки кода указывают на статичность и принадлежность к рассматриваемому «главному» элементу, для обращения к ним нужно использовать имя User.Type_Admin. Если попытаться обратиться через экземпляр, код возвращает undefined.
Методы
Добавить классы в код – не самая трудная задача. Она требует хранения информации, которая будет использоваться приложением. На помощь приходят методы. Это – функции, которые выполняют те или иные операции с имеющимися данными. Могут быть как «экземплярными», так и статичными.
Методы экземпляра
Они имеют доступ к данным класса. Могут вызывать другие методы:
Здесь есть класс User. У него – метод getName. Как и в функции constructor this внутри метода ссылается на созданный «элемент» classes. А вот метод, который вызывает «себеподобный»:
Методы, как и поля, бывают приватными.
Геттер и сеттерГеттеры и сеттеры – специальные методы, срабатывающие автоматически при обращении к полям для получения или корректировки имеющихся значений. Они имитируют обычное поле, но с большим контролем доступа:
- getter – выполняется, когда происходит попытка получения значения полей;
- setter – работает при установлении значения.
Выше – пример проверки на факт того, что name не является пустым элементом программного кода.
Статичные методы
Относятся непосредственно к классу. В них должна просматриваться логика, актуальная для всех будущих экземпляров. Необходимо помнить следующие принципы:
- статичные методы обладают доступом к статичным полям;
- не имеют доступа к полям экземпляра.
Встречаются как «публичные», так и приватные вариации. Составляются точно так же, как и при работе со статичными приватными свойствами.
Наследование
Еще один важный элемент написания программы – это наследование. Задается в JS при помощи ключевого слова extends. Надпись class Child extend Parent указывает на то, что элемент Child выступает наследником от class Parent. Происходит передача функции-конструктора, полей, методов.
Здесь Admin унаследовал функцию-конструктор, метод getName() и поле name. У него имеется и собственный элемент status, выступающий в качестве свойства.
Родитель: конструктор и класс
Если добавить в код класс наследник, то для инициализации потребуется вызвать функцию super(). Она отвечает за вызов конструктора класса-родителя.
Также в JS дочерние classes могут использовать ключевое слово super. Оно дает возможность вызова метода родителя:
Выше – пример того, как это выглядит в редакторе. Есть class User, а у него метод – renderProperties. Последний получает в виде аргумента элемент Node-дерева, а потом рендерит в него все поля. Наследник выглядит в этом случае так.
Классы | 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 или телеграмм чат, а также подписывайтесь на наши новости
Вопросы:
Какое ключевое🗝️ слово для определения класса?
constructor()
class
this
Методы внутри класса разделяются ли запятой.
true
false
Сколько методов constructor()
может находится в одном классе?
- Неограниченно
- До десяти
- Только один
Для того чтобы понять, на сколько вы усвоили этот урок, пройдите тест в мобильном приложении нашей школы по этой теме или в нашем телеграм боте.
Ссылки:
- MDN web docs
- Learn JavaScript
Contributors ✨
Thanks goes to these wonderful people (emoji key):
Philipp Dvinyaninov 📖 | Dmitriy Vasilev 💵 | Resoner2005 🐛 🎨 🖋 | Navernoss 🖋 🐛 🎨 |
классов JavaScript | SamanthaMing.com
Когда я говорю «Классы», вы можете сказать «УРА» 🎊 JS наконец представила новую объектно-ориентированную модель наследования. Ну, не совсем так. Он по-прежнему использует существующее наследование на основе прототипов (обозначено на фотографии как «Старое»). Но теперь это больше похоже на объектно-ориентированное программирование (ООП). Yay, я думаю, что этот синтаксический сахар БОЛЬШОЙ!
- Определение класса
- Создание экземпляра класса
- Статические методы и методы экземпляра
- Нет функции стрелки
- Функция стрелки не имеет свойства прототипа
- Функция стрелки не имеет нового оператора
- Сахар вреден для вас!
- Вклад сообщества
- Ресурсы
Определение класса
Для тех, кто пришел из объектно-ориентированного программирования, тогда все в порядке. Но для тех, кто плохо знаком с этим или просто хочет дружеское напоминание. Первым шагом является создание нашего класса. Ключевое слово для использования: class
.
Конструктор : Это специальный метод для инициализации экземпляра этого класса. Это означает, что всякий раз, когда мы создаем новый экземпляр класса, он вызывает конструктор. Это отличное место для установки некоторых свойств и назначения параметров. В нашем примере мы хотим убедиться, что когда кто-то создает новый экземпляр Meal
, у него есть костюм.
Метод-прототип : Метод-прототип — это метод, доступный только при создании экземпляра класса. Это станет ясно, когда я покажу вам пример позже.
Статический метод : Статический метод — это то, что вы можете вызывать без создания экземпляра класса. Подробнее об этом позже.
Создать экземпляр класса
Отлично, теперь вы создали класс. Давайте создадим его экземпляр , используя ключевое слово new
.
Теперь мы можем вызвать наш метод-прототип:
⚠️ Но! вы не можете получить доступ к статическим методам.
Это связано с тем, что статические методы недоступны экземпляру. Это может быть вызвано только классом
Итак, вы, должно быть, задаетесь вопросом, когда следует использовать статические или экземплярные методы. Вот очень простой ответ. Используйте статические методы, если вы не хотите создавать экземпляр класса. Лол, я знаю, что это не очень удовлетворительный ответ. Большую часть времени вы будете видеть статические методы, используемые для создания служебных функций для приложения. В любое другое время лучше придерживаться метода экземпляра.
Нет функции стрелки
Еще одна интересная вещь, представленная в ES6, — это функция стрелки 9.0003
MDN: Выражение стрелочной функции — это синтаксически компактная альтернатива обычному функциональному выражению, хотя и без собственных привязок к ключевым словам this, arguments, super или new. target. Выражения стрелочных функций плохо подходят в качестве методов, и их нельзя использовать в качестве конструкторов.
Стрелочная функция не имеет свойства прототипа
Таким образом, обратите внимание, что в несахарном способе мы использовали ключевое слово функции
:
Стрелочная функция не имеет свойство прототипа
, поэтому мы не можем использовать функцию стрелки.
У стрелочной функции нет нового оператора
Во-вторых, стрелочные функции нельзя использовать в качестве конструкторов.
Итак, вот еще один, где вы должны использовать обычный синтаксис функции
.
Сахар вреден!
Некоторые из вас могут возразить, что класс
— это плохо, потому что он скрывает истинную природу JS. И я думаю, что это абсолютно справедливое замечание. Давайте вернемся к намерению классов. Он был введен, чтобы облегчить изучение JavaScript 👍
Для тех, кто перешел с объектно-ориентированного языка программирования, такого как Ruby или Python, это значительно облегчит переход к изучению JS благодаря знакомому синтаксису. Для новичков это будет означать, что они быстрее разовьются и будут готовы к работе. А как только вы начнете, надеюсь, вам захочется глубже погрузиться в JS и узнать, что на самом деле скрывается под капотом 🤓
Но от ложечки сахара лекарство перестает действовать…🎶
Изучение нового языка сложно, поэтому, если мы сможем немного облегчить этот процесс, я думаю, это будет здорово. Очень легко быть ошеломленным, когда на тебя все бросают. Это как пытаться пить из пожарного шланга, в итоге ты вообще не пьешь воды. Вот почему обучающие программы выполняются пошагово. Никто не переходит от белого пояса к черному поясу сразу. Вы должны пройти через этот процесс, он требует времени.
Итак, следует ли использовать класса
? — Ну, это зависит от вас и вашей команды. Как я всегда говорю, правильного пути не бывает; как правильно всегда зависит 😉 Давайте не будем сразу отмахиваться от «сахара» как от плохого. Как разработчики, мы всегда должны быть открыты для новых идей. Меньше суждений, больше слушания и предполагайте благие намерения 😊
Обратите внимание, когда вы используете тип из
в классе, он вернет функцию
.
Спасибо @ianwijma
Ресурсы
- MDN Веб -документы: классы
- W3Schools: Классы
- Функция стрелки №
- Понимание классов в Javascript
- Extingjs: классы
- . Частные и общедоступные поля класса JavaScript
Моя любимая часть сообщества JavaScript — это то, что все, кажется, всегда спрашивают «почему?» . Почему мы делаем вещи так, как мы их делаем? Как правило, ответ на этот вопрос полон разума и исторического контекста. Но иногда ответ бывает проще — «потому что мы всегда так делали».
В предыдущем посте мы узнали, как создавать классы JavaScript как в ES5, так и в ES6. Мы также обсудили, как добавить состояние к экземплярам этих классов через конструктор, а также как совместно использовать методы между экземплярами через прототип классов. Вот простой класс
Player
, который включает в себя все, что мы обсуждали в отношении классов ES6.class Player {
конструктор() {
this.points = 0
this.assists = 0
this.rebounds = 0
this.steals = 0
}
addPoints(amount) {
this.points += amount
}
addAssist() {
this.assists++
}
addRebound() {
this.rebounds++
}
addSteal() {
this.steals++
}
}
Глядя на этот код, можем ли мы сделать его немного более интуитивным? Методы прекрасны, они приходят довольно естественно. А конструктор? Что вообще такое
конструктор
и почему мы должны определять значения экземпляра там? Теперь есть ответы на эти вопросы, но почему мы не можем просто добавить состояние к нашим экземплярам, как мы это сделали с методами? Что-то вроде этогоClass Player {
очков = 0
передачи = 0
подборы = 0
кражи = 0
AddPoints (сумма) {
this. points += сумма
}
Addassist () {
}
() {
}
() {
}
()
это.assists++
}
addRebound() {
this.rebounds++
}
addSteal() {
this.steals++
}
}
3
3
Оказывается, это основа для предложения по объявлению полей классов, которое в настоящее время находится на этапе 3 процесса TC-39. Это предложение позволит вам добавлять свойства экземпляра непосредственно как свойство класса без использования метода конструктора
class PlayerInput extends Component {
конструктор (реквизит) {
супер (реквизит)
this.state = {
имя пользователя: ''
}
this.
handleChange) (this.handleChange)}
handleChange(event) {
this.setState({
username: event.target.value
})
}
render() {
...
}
}
PlayerInput.propTypes = {
ID: Proptypes.String.Isrequired,
Метка: Proptypes.String.Isrequired,
OnSubmit: Proptypes.func.Isrequired,
}
PlayerInput.DefaultProps = {
}
. }
Давайте посмотрим, как новое предложение
Class Fields
улучшает приведенный выше код. Во-первых, мы можем взять нашу переменнуюсостояния
из конструктора и определить ее непосредственно как свойство (или «поле») в классе.класс PlayerInput extends Component {
состояние = {
имя пользователя: ''
}
конструктор (реквизит) {
супер (реквизит)
this.handleChange = this.handleChange (0this2) 90d.bine.bin
Handlechange (Event) {
This. SetState ({
Имя пользователя: Event.target.value
})
}
render () {
...
}
}
...
}
}
... .propTypes = {
идентификатор: PropTypes.string.isRequired,
метка: PropTypes.string.isRequired,
onSubmit: PropTypes.func.isRequired,
}
PlayerInput.defaultProps = {
метка: «Имя пользователя»,
-
}
Круто, но не из-за чего слишком волноваться. Давайте продолжим. В предыдущем посте мы говорили о том, как вы можете добавить статические методы к самому классу, используя ключевое слово
static
. Однако, согласно спецификации класса ES6, это работает только с методами, а не со значениями. Вот почему в приведенном выше коде мы должны добавитьpropTypes
иdefaultProps
доPlayerInput
после того, как мы его определим, а не в теле класса. Опять же, почему они не могут работать непосредственно с телом класса, как статический метод? Что ж, хорошая новость заключается в том, что это также включено в предложениеClass Fields
. Итак, теперь вместо того, чтобы просто определять статические методы в теле класса, вы также можете определять статические значения. Для нашего кода это означает, что мы можем перемещатьpropTypes
иdefaultProps 9.0030 до определения класса.
Class PlayerInput Extends Component {
Static Proptypes = {
ID: Proptypes.String.Isrequired,
Метка: Proptypes.String.Isrequired,
Onsubmit: Proptypes.func. = {
метка: 'Имя пользователя'
}
состояние = {
имя пользователя: ''
}
конструктор (реквизит) {
супер(реквизит)
this.handleChange = this.handleChange.bind(this)
}
handleChange(event) {
this.setState({
имя пользователя: event.target.value
}) 0
})
}
} ) {
...
}
}
Намного лучше, но у нас все еще есть уродливый метод
конструктора
и вызовsuper
. Опять же, причина, по которой нам нужен конструктор прямо сейчас, заключается в том, чтобы связатьhandleChange
в правильный контекст. Если бы мы могли придумать другой способ убедиться, чтоhandleChange
всегда вызывается в правильном контексте, мы могли бы вообще избавиться от конструктораЕсли вы раньше использовали стрелочные функции, то знаете, что у них нет собственного ключевого слова
this
. Вместо этогоэто ключевое слово
связанолексически
. Это причудливый способ сказать, что когда вы используете ключевое словоthis
внутри стрелочной функции, все ведет себя так, как вы ожидаете. Взяв это знание и объединив его с предложением «Поля классов», что, если мы поменяем местамиметод handleChange
для функции стрелки? Кажется немного странным, но, сделав это, мы полностью избавимся от проблемы.bind
, поскольку, опять же, стрелочные функции связываютс
лексически.Class PlayerInput Extends Component {
Static Proptypes = {
ID: Proptypes.String.Isrequired,
Метка: Proptypes.String. = {
метка: 'Имя пользователя'
}
состояние = {
имя пользователя: ''
}
handleChange = (event) => {
thisusername.setState.setState({
2 thisusername.setState.3
})
}
render() {
...
}
}
Ну, вы бы посмотрели на это? Это на намного лучше, чем исходный класс, с которого мы начали, и все это благодаря предложению Class Fields, которое скоро станет частью официальной спецификации EcmaScript.
С точки зрения разработчиков, поля классов — это явное преимущество. Однако у них есть некоторые недостатки, о которых редко говорят. В прошлом посте мы говорили о том, что классы ES6 — это просто сахар по сравнению с тем, что мы назвали «псевдоклассическим» шаблоном. Это означает, что когда вы добавляете метод в класс, это действительно похоже на добавление метода в прототип функции.
class Animal {
eat() {}
}
// Эквивалентно
function Animal () {}
Animal.prototype.eat = функция () {}
Это эффективно, потому что
eat
определяется один раз и совместно используется всеми экземплярами класса. Какое это имеет отношение к полям класса? Итак, как мы видели выше, в экземпляр добавляются поля класса. Это означает, что при использовании полей класса для каждого экземпляра, который мы создаем, мы будем воссоздавать все методы в памяти.класс животных {
есть () {}
спать = () => {}
}
// Эквивалентно
function Animal () {
this.sleep = function () {}
}
Animal.prototype.eat = function () {}
Обратите внимание, что
sleep
помещается в экземпляр, а не вAnimal. prototype
. Это плохая вещь? Что ж, это может быть. Делать общие заявления о производительности без измерения, как правило, плохая идея. Вопрос, на который вы должны ответить в своем приложении, заключается в том, перевешивает ли опыт разработчика, который вы получаете от Class Fields, потенциальное снижение производительности.Если вы хотите использовать что-либо из того, о чем мы говорили до сих пор, в своем приложении, вам необходимо использовать подключаемый модуль babel-plugin-transform-class-properties.
Другим аспектом предложения Class Fields являются «частные поля». Иногда, когда вы создаете класс, вы хотите иметь частные значения, которые не видны внешнему миру. Исторически сложилось так, что в JavaScript, поскольку нам не хватало возможности иметь действительно частные значения, мы помечали их символом подчеркивания.
Класс CAR {
_milesDriven = 0
Drive (расстояние) {
This. _Milesdriven += Расстояние
}
Getmilesdriven () {
Это.
В приведенном выше примере мы полагаемся на потребителя класса
Car
для получения данных о пробеге автомобиля путем вызова методаgetMilesDriven
. Однако, поскольку на самом деле ничто не делает_milesDriven
приватным, любой экземпляр может получить к нему доступ.const tesla = new Car()
tesla.drive(10)
console.log(tesla._milesDriven)
Существуют причудливые (хакерские) способы обойти эту проблему с помощью WeakMaps, но было бы неплохо, если бы существовало более простое решение. Опять же, предложение Class Fields приходит нам на помощь. По предложению можно создать приватное поле с помощью #. Да, вы правильно прочитали, # . Давайте посмотрим, что это делает с нашим кодом
.Class Car {
#MilesDriven = 0
Drive (расстояние) {
Это.