Объекты глубже: методы и this
Вы уже знаете, что объект — это набор свойств. Но объекты умеют гораздо больше: они могут содержать функции — и тогда эти функции называют методами. Именно методы делают объекты «живыми» и дают им поведение. А чтобы метод знал, с какими данными работать, существует ключевое слово this.
🔧 Метод — это функция внутри объекта
Давайте начнём с самого простого. Вы уже знаете, как создать объект с обычными свойствами — числами, строками, булевыми значениями:
const user = {
name: "Алексей",
age: 28,
isPremium: true
};
Это статические данные — они хранят информацию, но ничего не делают. А теперь представьте, что мы хотим, чтобы объект умел приветствовать. Звучит немного по-мультяшному, но идея абсолютно практичная. Для этого в объект можно положить функцию:
const user = {
name: "Алексей",
age: 28,
greet: function() {
console.log("Привет! Меня зовут Алексей.");
}
};
user.greet(); // Привет! Меня зовут Алексей.
Вот и всё! Функция внутри объекта называется методом. Синтаксис вызова — через точку: объект.метод(). Вы уже делали это тысячу раз — console.log(), arr.push(), str.toUpperCase() — это всё методы!
💡 Запомните: если значение свойства — это функция, свойство называется методом. Метод — это функция, принадлежащая объекту.
В современном JavaScript (ES6+) есть более краткая запись методов — без слова function:
const user = {
name: "Алексей",
age: 28,
greet() { // краткий синтаксис — рекомендуется
console.log("Привет, мир!");
},
sayAge() {
console.log("Мне 28 лет.");
}
};
user.greet(); // Привет, мир!
user.sayAge(); // Мне 28 лет.
Оба варианта работают одинаково — краткая запись просто чище и читабельнее. Используйте её в новом коде.
🔍 Ключевое слово this — «я сам»
Вернёмся к методу greet. Там мы жёстко вписали строку "Привет! Меня зовут Алексей.". Но что если у нас будет сто пользователей? Нам что, для каждого писать отдельную функцию? Конечно нет.
Метод должен уметь обращаться к свойствам своего объекта — к имени, возрасту, другим данным. Для этого существует this.
🎯 this — это ссылка на объект, в контексте которого был вызван метод. Проще говоря: когда вы пишете this внутри метода, вы имеете в виду этот самый объект.
Посмотрим на примере:
const user = {
name: "Алексей",
age: 28,
greet() {
console.log("Привет! Меня зовут " + this.name + ".");
// this.name — обращение к свойству name этого объекта
},
introduce() {
console.log(`Я ${this.name}, мне ${this.age} лет.`);
}
};
user.greet(); // Привет! Меня зовут Алексей.
user.introduce(); // Я Алексей, мне 28 лет.
Когда JavaScript выполняет user.greet(), он автоматически устанавливает this равным user. Поэтому внутри метода this.name — это то же самое, что user.name.
Почему нельзя просто написать user.name вместо this.name прямо внутри метода? Технически можно — но это плохая практика. Что если объект переименуют? Что если этот метод скопируют в другой объект? С this код работает универсально, он всегда ссылается на «текущий объект».
greet() {
console.log(
"Привет, " + user.name
);
}
greet() {
console.log(
"Привет, " + this.name
);
}
🏦 Практика: объект «Банковский счёт»
Теперь создадим реальный, полезный пример — объект банковского счёта. У него будут свойства (владелец, баланс) и методы (пополнить, снять, посмотреть баланс). Это отличная иллюстрация того, как данные и поведение живут вместе в одном объекте.
const account = {
owner: "Мария Петрова",
balance: 15000,
deposit(amount) {
if (amount <= 0) {
console.log("Сумма пополнения должна быть больше нуля.");
return;
}
this.balance += amount;
console.log(`Пополнено на ${amount} ₽. Баланс: ${this.balance} ₽`);
},
withdraw(amount) {
if (amount <= 0) {
console.log("Сумма снятия должна быть больше нуля.");
return;
}
if (amount > this.balance) {
console.log("Недостаточно средств!");
return;
}
this.balance -= amount;
console.log(`Снято ${amount} ₽. Баланс: ${this.balance} ₽`);
},
getBalance() {
console.log(`${this.owner}, ваш баланс: ${this.balance} ₽`);
return this.balance;
}
};
account.getBalance(); // Мария Петрова, ваш баланс: 15000 ₽
account.deposit(5000); // Пополнено на 5000 ₽. Баланс: 20000 ₽
account.withdraw(3000); // Снято 3000 ₽. Баланс: 17000 ₽
account.withdraw(50000); // Недостаточно средств!
account.getBalance(); // Мария Петрова, ваш баланс: 17000 ₽
Разберём детально, что происходит в методе deposit:
deposit(amount)— метод принимает аргумент, сколько пополнить- Проверяем, что сумма положительная — защита от ошибок
this.balance += amount— изменяем баланс этого объекта- Выводим сообщение с текущим
this.balance— данные уже обновлены
Обратите внимание: методы не просто читают this — они могут его изменять. this.balance += amount реально меняет свойство объекта. Это и есть «поведение» объекта — он реагирует на внешние действия и сам меняет своё состояние.
⚠️ Важно: this — это не копия объекта, а именно ссылка на него. Поэтому изменения через this.balance = ... реально меняют исходный объект.
⚠️ Почему стрелочные функции не подходят для методов
Вы знаете стрелочные функции: () => {}. Они удобны и компактны. Но для методов объекта их нельзя использовать. Давайте разберёмся почему — это одна из самых частых ловушек для новичков.
Посмотрим на проблему в коде:
const user = {
name: "Игорь",
greet: () => {
// Стрелочная функция — ОШИБКА!
console.log("Привет, " + this.name);
}
};
user.greet(); // Привет, undefined
Почему undefined? Всё дело в том, как стрелочные функции работают с this.
Имеет своё значение this. При вызове как метода obj.method(), this автоматически становится равным obj. Именно это нам нужно.
Не имеет своего this. Она берёт this из окружающего контекста (обычно это глобальный объект или undefined в строгом режиме). Для метода это катастрофа.
Это сознательное дизайнерское решение — стрелочные функции были созданы именно для случаев, когда нужно сохранить внешний this, а не создать новый. Они отлично подходят для колбэков внутри методов:
const timer = {
seconds: 0,
start() {
// Здесь this = timer ✓
setInterval(() => {
// Стрелочная функция берёт this из start()
// то есть this по-прежнему = timer ✓
this.seconds++;
console.log(`Прошло ${this.seconds} сек.`);
}, 1000);
}
};
timer.start();
Если бы внутри setInterval была обычная функция, this там потерялся бы. Стрелочная функция — идеальный колбэк именно потому, что «прозрачна» для this.
✅ Правило: для методов объекта — только обычные функции (function или краткий синтаксис method() {}). Стрелочные функции — для колбэков внутри методов.
➕ Динамическое добавление методов
Объекты в JavaScript гибкие — методы можно добавлять уже после создания объекта. Это называется динамическим добавлением:
const car = {
brand: "Toyota",
speed: 0
};
// Объект создан, теперь добавим метод
car.accelerate = function(kmh) {
this.speed += kmh;
console.log(`${this.brand} разгоняется. Скорость: ${this.speed} км/ч`);
};
car.brake = function() {
this.speed = 0;
console.log(`${this.brand} остановился.`);
};
car.accelerate(60); // Toyota разгоняется. Скорость: 60 км/ч
car.accelerate(40); // Toyota разгоняется. Скорость: 100 км/ч
car.brake(); // Toyota остановился.
Синтаксис простой: объект.новыйМетод = function() { ... }. После этой строки у объекта появляется новый метод.
Это удобно, но не злоупотребляйте: если структура объекта известна заранее, лучше определить все методы при создании. Динамическое добавление полезно в особых ситуациях — когда поведение нужно добавить условно или «по требованию».
🔑 Кстати, удалить метод из объекта можно оператором delete: delete car.brake — и метода больше нет.
🌐 this зависит от того, КАК вызвана функция
Самое коварное в this — его значение зависит не от того, где функция написана, а от того, как она вызвана. Рассмотрим интересный пример:
function greet() {
console.log("Привет, " + this.name);
}
const userA = { name: "Анна", greet: greet };
const userB = { name: "Борис", greet: greet };
userA.greet(); // Привет, Анна (this = userA)
userB.greet(); // Привет, Борис (this = userB)
Одна и та же функция greet — но при вызове через разные объекты она видит разный this! Когда мы пишем userA.greet(), JavaScript перед вызовом функции смотрит: «что стоит слева от точки?» Это userA — значит, this = userA.
⚠️ Ловушка потери контекста: если вы «оторвёте» метод от объекта и вызовете его как обычную функцию, this потеряется:
const fn = userA.greet;
fn(); // Привет, undefined — this потерян!
Это продвинутая тема — как это фиксить через bind, call, apply — будет в следующих уроках. Сейчас главное запомнить: вызывайте методы только через объект, и this всегда будет правильным.
✅ Итоги урока
- Метод — это функция, которая является свойством объекта. Вызывается через точку:
obj.method() - Краткий синтаксис методов:
methodName() {}— предпочтительный вариант thisвнутри метода — ссылка на объект, через который вызван метод- Через
thisметоды читают и изменяют свойства своего объекта - Стрелочные функции не имеют своего
this— не используй их как методы объекта - Методы можно добавлять к объекту динамически:
obj.newMethod = function() {} thisопределяется в момент вызова: что стоит слева от точки — тот и естьthis
В следующем уроке разберём геттеры и сеттеры — специальные методы, которые выглядят как обычные свойства, но работают как функции. 🚀
Методы и this
7 вопросов