В этом теоретическом уроке мы познакомимся с ключевым словом this, классами, а также изучим что такое Объектно-ориентированное программирование.
Итак, Начнем с ключевого слова this. Данное слово обычно используется в методах, и хранит ссылку на тот объект, которому принадлежит этот метод. Например, давайте создадим какой-нибудь объект. Пусть будет cat.
У данного объект будет одно свойство и один метод. В методе мы просто хотим в консоле вывести имя кота. Чтобы получить доступ к имени кота, мы можем написать так, или вместо имени объекта использовать ключевое слово this. Так как этот метод относится к объекту cat, то ключевое слово this будет хранить ссылку на объект. Слово this мы можем писать и не в метода, хотя так обычно не делают. Если мы просто напишем this и нажмем Enter то консоль вернет объект Window, так как сейчас this принадлежит объекту Window. Хотя некоторые браузеры могут возвратить undefined, так как считается, что небезопасно ссылаться на объект Window через this. Но вы можете спросить, а зачем вообще этот this нужен. Он в основном нужен для создания классов, что является нашей второй темой.
Когда вы будите писать большие программы, например, компьютерные игры, вы столкнетесь с ситуацией когда необходимо создать много схожих объектов, которые имеют одинаковые ключи, но разные значения. Например, надо будет создать много врагов, у которых есть, например, уровень, имя, способ атаки и т.д. И вам надо будет под каждого типа врага создавать отдельные объекты с одинаковыми ключами, но разными значениями, что будет очень утомительно. Здесь на помощь и приходят классы, с помощью которых вы можете создать шаблон для объектов и по этому шаблону будет очень легко создавать новые объекты. Сейчас вы это увидите.
Чтобы создать класс, нам в начале необходимо написать ключевое слово class, затем пишем имя. Пусть будет Enemies, т.е. Враги. Имена классов принято писать с большой буквы. Далее ставим фигурные скобки, теперь через точку с запятой перечисляем нужные нам свойства, пусть это будут level и name, т.е. уровень и имя. Точки с запятой, как это сейчас сделал я можно не ставить в классах между свойствами и методами. Их надо ставить только тогда когда вы хотите придать значения свойствам. Например так.
Далее создадим метод, который будет выводит атаку в консоль. Пусть будет текст КИЯ!!! Теперь мы должны написать специальную функцию, которая и будет создавать на основе класса объекты. Функция эта называется constructor. С помощью неё при создании объекты мы сразу можем придать значения его свойствам. В параметрах указываем какие значения нам нужны. Это будет значение уровня, т.е. пишем plevel, и pname. Далее в фигурных скобках присваиваем аргументы которые введет пользователь соответствующим ключам объекта. Только мы же не знаем как пользователь назовет объект, чтобы к нему обратиться, и здесь как раз таки на помощь приходит колючевое слово this. Пишем thid
Теперь создадим на основе этого класса объект. Объект будет называться, допустим greenMonster. Чтобы вызвать функцию конструктор нам надо сперва написать ключевое слово new, затем имя класса, которая является и именем конструктора. Далее в скобках вводим аргументы. Допустим уровень будет 100, а имя будет “Боб”.
Вот так теперь быстро можно создавать объекты. Кстати, когда вы создаете класс, можно свойство не перечислять через точку с запятой, а просто сразу в конструкторе присвоить им значения, и тогда транслятор поймёт что вы хотели и сам их создаст. это не является ошибкой. Написать.
А что будет, если пользователь введет только уровень, или не введет ничего. Тогда конструктор присвоит свойствам объекта, где не введены аргументы, значение undefined.
Теперь рассмотрим другую ситуацию, допустим нам необходимо чтобы пользователь в параметре уровня ввел только число, не текст или что-то другое, что в итоге возвращает не число. Это конечно можно сделать с помощью условного оператора if и одного унарного оператора. Давайте напишем этот код.
Чтобы проверить, является аргумент числом, мы используем унарный оператор typeof. Как вы могли заметить, унарные операторы это не только знаки типа + и -, но ими могут быть целые слова и сочетания слова. Оператор typeof ставится перед операндом и возвращает его тип в виде строки. Итак, если это число то присвой его необходимому свойству, а если нет, то выведи сообщение в консоль и присвой свойству значение null.
Но на самом деле так не принято проверять значение аргумента для свойств в классах, а принято это делать с помощью так называемых гетеров и сеттеров. Вы можете – а в чем тогда преимущества так называемых геттеров и сеттеров о которых мы еще не знаем над простым условным оператором if внутри конструктора. Дело в том что при создании объекта вы как пользователь не сможете присвоить свойству level текст, но можете это сделать после создания объекта, так как теперь эта проверка не будет работать.
Т.е. функция-конструктор сработает только раз. Но вот гетеры и сеттеры работают всегда. Давайте же наконец таки их изучим.
Геттеры и сеттеры это специфические функции, которые помогают выполнить дополнительные действия при чтении или записи значений в свойства объекта.
С помощью сетера мы будем задавать значение для свойства объекта, а спомощью гетера – получать значение.
Итак начнем писать сеттер, вместо слова function мы должны написать ключевое слово set, затем имя сетера. Обычно гетеры и сеттеры называются именем того свойства, с которым они работают, но чтобы понять где мы именно используем геттеры я назову его чуть по другому, просто спереди напишу две буквы gs.
А все остальное похоже на то, что мы уже делали в обычных функциях: параметров у сетера не будет, внутри фигурных скобок пишем необходимый код.
Теперь пишем геттер, он просто будет возвращать значение поля. Далее в конструкторе мы должны написать вместо свойства объекта, имя его гетера-сетера. Как я говорил, это специфическая функция, может так перехватывать переменную. Запускаем, создаем объект. И как видите, вышло сообщение в консоли, что мы ввели не число, и свойство level, стало равно 0. Теперь вызвать гетер и сеттер мы можем как обычное свойство. Но есть проблема, мы можем проигнорировать гетер и сеттер, просто напрямую обративший с полю. Что же делать?
Мы можем просто заблокировать поле, поставив спереди имени его решетку. Теперь к полю будет доступ только у гетера и сетера.
Как видите, значение вернулось как undefined, т.е. транслятор не выдет значение свойства level, так как оно теперь заблокировано. И так мы написать не можем.
Но прикол в том что в программном файле м так писать не можем, а в консоли можем. Дело в том что консоль предназначена для отладки кода, поэтому позволяет так писать, предоставляя вам больше возможностей. И как я говорил гетеры и сеттеры обычно называют именем свойства, так как так удобнее задавать им значения и читать их.
С сеттерами и гетерами мы закончили. Теперь давайте поговорим о наследовании.
Как вы уже знаете имя класса мы пишем с большой буквы, и могли заметить что некоторые прототипы также пишутся с большой буквы, например, Object или Window, а некоторые объекты с маленькой, например window, чей прототип Window с большой буквы. Почему так происходит. Дело в том что объекты, которые пишутся с большой буквы, одновременно являются и объектами и Классами. Т.е. когда мы создаем новый объект, мы можем написать фигурные скобки в значении, но можем также воспользоваться конструктором Object
Правда таким образом вы можете создать только пустой объект. Вы можете спросить, так если Object ведем тебя как класс, почему мы продолжаем называть его объектом. Так сложилось исторически. Дело в том, что классы в JavaScript появились в 2015, а до этого JavaScript использовал прототипы для реализации наследования, что отличалось от наследования других языков основанных на ООП (т.е. объектно-ориентированное программирование, о котором мы позже поговорим). Т.е. наследование в JavaScript называется прототипное наследование, а наследование в языках основанных на ООП называется классическое наследование, и оно основано на классах.
В силу того, что в JavaScript не было классов, объекты на основе прототипного наследования, наследовали свойства и методы у других объектов, таких как Object, Window и т.д. Но вот появились классы, и теперь по идее, можно было бы назвать все эти объекты Window, Document, Object и т.д. классами, но так не произошло. Дело в том, что под капотом наследования, в JavaScript все также наследуется на основе прототипов, а классы были добавлены для увеличения возможностей языка, но в своей основе они отличаются от классов в классическом наследовании. Поэтому мы не можем называть такие объекты как Object, Window и т.д. классами, так как они не соответствуют принципам ООП. Мы их продолжаем называть объектами, но воспринимаем их как классы. Поэтому я иногда говорю объект-класс. И все созданные вами классы также являются объектами из-за прототипного наследования.
В итоге принято все объекты с большой буквы воспринимать также как классы. Но из-за прототипного наследования, называть их классами в традиционном понимании мы не можем. Вот так все запутанно, но надеюсь я понятно объяснил.
Т.е. здесь Object выступает как объект методами которого мы можем пользоваться. Методы обычного класса мы не можем использовать пока не создадим на основе него объект. И потому что данные объекты являются классами, они и могут передавать свои методы и свойства дочерним классам, на основе которых создаются объекты. Вот теперь мы чуть лучше узнали как передаются свойства и методы от одного объекта, к другому, они передаются с помощью классов.
Вы можете спросить, а зачем нам объект window с маленькой буквы, если уже есть объект Window с большой? Дело в том, что транслятор браузера автоматически создает объект window на основе объекта-класса Window, чтобы получить доступ к окну текущего браузера, и предоставить вам все необходимые свойства и методы для работы с ним. Т.е. когда вы видите что есть объект с маленькой буквы и объект-класс с большой, то объект с маленькой буквы был создан заранее транслятором браузера, чтобы предоставить вам необходимые свойства и методы объекта-класса с большой буквы.
А как нам сделать так, чтобы новый класс наследовал свойства и методы от класса Enemies. Например, у нас в игре среди врагов будут выделяться летающие враги, которых будет много видов, и у всех будет функция лететь. Она не нужна другим врагам, поэтому в методе Enemies она не нужна, но будет хорошо если класс, например, FlyMonsters будет наследовать свойства и методы класса Enemies, и при этом у него будет метод fly. Это можно сделать с помощью ключевого слова extemds при создании класса.
Создаем новый класс.
Пусть у него будет еще свойство color где сы укажем цвет. Далее будет метод fly и конструктор, в который мы передадим свойства уровня, имени и цвета.
Для начала нам надо вызвать конструктор прототипа, который присвоит значения уровню и имени. Это делается с помощью ключевого слова super и в скобках передаем параметры. Далее присвоим параметр цвет свойству колор нашего класса. Готово.
Вы могли заметить, когда мы создавали класс Enemies в его конструкторе мы не писали ключевое слово super, чтобы вызвать конструктор Object. Хотя он является прототипом для Enemies. Дело в том что транслятор сам добавляет его автоматически без параметров, так как конструктору Object параметры не нужны.
Теперь создаем объект. Проверяем. Все работает!)
А что будет – эли мы напишем так?
Здесь мы получается просто даем ссылку на класс переменной, и теперь можем создавать экземпляр класса с помощью имени переменной.
Как я говорил, прямо из класса мы не можем обратится к его свойствам и методам. Но существуют так называемые статические методы и свойства, которые принадлежат классу, но не объектам. Более подробней о статических методах я расскажу на одном из следующих уроков.
Так вот у всех классов есть статическое свойство prototype. Данное свойство возвращает просто ваш класс, со всеми его методами и свойствами, который может быть прототипом для объекта или другого класса. Вот здесь пишет что это прототип класса Enemies, конструктор принадлежит классу FlyMonster. У него есть метод fly, пустое свойство color он здесь писать не будет.
А зачем это свойство нужно? Дело в том, что с помощью него мы можем добавлять в класс новые свойства и функции или изменять существующие. Например добавим свойство superPower со значением 0 и метод fall.
И теперь нашему объекту доступна и эта переменная и этот метод:
На последок хочу сказать, существует объект класс Function, а следовательно, как вы могли догадаться, функция тоже является объектом. И мы можем создать функцию через конструктор new Function.
Где первые параметры – это параметры нашей функции, а последний параметр – это тело нашей функции, где мы вернем результат сложения x и y. Проверяем.
А так как функция это объект, мы можем добавлять в него свойство и методы.
Т.е. можно сказать, что в JavaScript практически все является объектами или ведут себя как объекты (это касается примитивных типов данных, как число, строка и т.д.. Только операторы не являются объектами.
На этом урок заканчивается, до встречи на следующем уроке