Методы объекта, "this"
Объекты обычно создаются, чтобы представлять сущности реального мира, будь то пользователи, заказы и так далее:
// Объект пользователя let user = { name: "Джон", age: 30 };
И так же, как и в реальном мире, пользователь может совершать действия: выбирать что-то из корзины покупок, авторизовываться, выходить из системы, оплачивать и т.п.
Такие действия в JavaScript представлены свойствами-функциями объекта.
Примеры методов
Для начала давайте научим нашего пользователя user
здороваться:
let user = { name: "Джон", age: 30 }; user.sayHi = function() { alert("Привет!"); }; user.sayHi(); // Привет!
Здесь мы просто использовали Function Expression (функциональное выражение), чтобы создать функцию для приветствия, и присвоили её свойству user.sayHi
нашего объекта.
Затем мы вызвали её. Теперь пользователь может говорить!
Функцию, которая является свойством объекта, называют методом этого объекта.
Итак, мы получили метод sayHi
объекта user
.
Конечно, мы могли бы заранее объявить функцию и использовать её в качестве метода, примерно так:
let user = { // ... }; // сначала объявляем function sayHi() { alert("Привет!"); } // затем добавляем в качестве метода user.sayHi = sayHi; user.sayHi(); // Привет!
Объектно-ориентированное программирование
Когда мы пишем наш код, используя объекты для представления сущностей реального мира, – это называется объектно-ориентированное программирование или сокращённо: «ООП».
ООП является большой предметной областью и интересной наукой само по себе. Как выбрать правильные сущности? Как организовать взаимодействие между ними? Это – создание архитектуры, и есть хорошие книги по этой теме, такие как «Приёмы объектно-ориентированного проектирования. Паттерны проектирования» авторов Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидес или «Объектно-ориентированный анализ и проектирование с примерами приложений» Гради Буча, а также ещё множество других книг.
Сокращённая запись метода
Существует более короткий синтаксис для методов в литерале объекта:
// эти объекты делают одно и то же (одинаковые методы) user = { sayHi: function() { alert("Привет"); } }; // сокращённая запись выглядит лучше, не так ли? user = { sayHi() { // то же самое, что и "sayHi: function()" alert("Привет"); } };
Как было показано, мы можем пропустить ключевое слово "function"
и просто написать sayHi()
.
Нужно отметить, что эти две записи не полностью эквивалентны. Есть тонкие различия, связанные с наследованием объектов (что будет рассмотрено позже), но на данном этапе изучения это неважно. В большинстве случаев сокращённый синтаксис предпочтителен.
Ключевое слово «this» в методах
Как правило, методу объекта необходим доступ к информации, которая хранится в объекте, чтобы выполнить с ней какие-либо действия (в соответствии с назначением метода).
Например, коду внутри user.sayHi()
может понадобиться имя пользователя, которое хранится в объекте user
.
Для доступа к информации внутри объекта метод может использовать ключевое слово this
.
Значение this
– это объект «перед точкой», который использовался для вызова метода.
let user = { name: "Джон", age: 30, sayHi() { // this - это "текущий объект" alert(this.name); } }; user.sayHi(); // Джон
Здесь во время выполнения кода user.sayHi()
значением this
будет являться user
(ссылка на объект user
).
Технически также возможно получить доступ к объекту без ключевого слова this
, ссылаясь на него через внешнюю переменную (в которой хранится ссылка на этот объект):
let user = { name: "Джон", age: 30, sayHi() { alert(user.name); // используем переменную "user" вместо ключевого слова "this" } };
Но такой код будет ненадёжным. Если мы решим скопировать ссылку на объект user
в другую переменную, например, admin = user
, и перезапишем переменную user
чем-то другим, тогда будет осуществлён доступ к неправильному объекту при вызове метода из admin
.
let user = { name: "Джон", age: 30, sayHi() { alert( user.name ); // приведёт к ошибке } }; let admin = user; user = null; // обнулим переменную для наглядности, теперь она не хранит ссылку на объект. admin.sayHi(); // Ошибка! Внутри sayHi() используется user, которая больше не ссылается на объект!
Если мы используем this.name
вместо user.name
внутри alert
, тогда этот код будет работать.