Методы объектов JavaScript и this
Методы объектов JavaScript и ключевое слово this: определение методов, разрешение this во время вызова, заимствование методов, цепочки вызовов, стрелочные и обычные функции.
Введение в методы объектов JavaScript
Объекты JavaScript — это коллекции свойств, а методы объектов — это функции, хранящиеся как свойства этих объектов. Методы позволяют объекту действовать с собственными данными, а не только хранить их.
В этом руководстве рассматривается, как определять и вызывать методы, как ключевое слово this связывает метод с его объектом, как читать и изменять состояние объекта изнутри методов, а также наиболее распространённая ловушка в языке: потеря this в колбэках. В конце разбирается практическое различие между обычными функциями и стрелочными функциями.
Определение и вызов методов
Метод — это просто свойство, значение которого является функцией. Сокращённый синтаксис greet() { ... } — современный способ его записи; он эквивалентен greet: function() { ... }.
greet — это метод объекта user. Он использует this.name для доступа к свойству name объекта, демонстрируя, как методы могут работать с данными внутри собственного объекта. Метод вызывается с той же точечной нотацией, что и любое свойство, с добавлением (): user.greet().
Ключевое слово this в методах
Ключевое слово this ссылается на объект перед точкой в момент вызова метода. Оно определяется во время вызова, а не в момент написания функции — именно это делает this гибким, но в то же время потенциально опасным источником ошибок.
Пример: использование this в методах
В методе details ключевое слово this ссылается на сам объект person, обеспечивая доступ к его свойствам name и age для формирования персонализированного сообщения. Поскольку details был вызван как person.details(), this равно person.
Изменение свойств объекта
Методы предназначены не только для получения значений свойств, но и для их обновления.
Пример: обновление свойств
Метод promote обновляет свойство jobTitle и выводит сообщение, отражающее это изменение. Это демонстрирует, как методы могут динамически изменять внутреннее состояние объекта.
Использование методов для вычислений
Методы также удобны для выполнения вычислений на основе свойств объекта.
Пример: вычисление значений
Метод area вычисляет площадь прямоугольника, используя свойства width и height. Этот пример показывает, как методы могут инкапсулировать функциональность, работающую с данными, хранящимися внутри объекта.
Заимствование методов
Поскольку this определяется во время вызова, одна и та же функция может работать с разными объектами. Именно на этом основано заимствование методов.
Пример: заимствование метода
Здесь метод speak объекта dog присваивается объекту cat. При вызове как cat.speak() значение this.name ссылается на Whiskers, демонстрируя, что this зависит от того, как вызывается метод, а не от того, где он был определён.
Если переназначить метод нельзя, но нужно его заимствовать, используйте call, apply или bind, чтобы явно задать this. Подробнее см. в статье Декораторы и переадресация, call/apply.
introduce.call(alice) запускает introduce с this, установленным в alice, даже несмотря на то, что introduce — самостоятельная функция и не является свойством ни одного из объектов.
Цепочки вызовов методов
Цепочки вызовов методов позволяют вызывать несколько методов в одном выражении: для этого каждый метод должен возвращать this — сам объект. Возвращённый объект становится целью следующего вызова.
Пример: реализация цепочки вызовов
Каждый метод в calculator изменяет value и возвращает объект, что делает возможными цепочки вызовов. Этот паттерн повышает читаемость кода и лежит в основе fluent API, таких как jQuery и многих вспомогательных методов для работы с массивами.
Обычные функции и стрелочные функции
В JavaScript поведение ключевого слова this существенно различается для обычных функций и стрелочных функций. Понимание этого различия — самое важное для написания безошибочного кода, зависящего от this.
Всегда будьте осторожны с потерей контекста this в колбэках или при передаче метода в качестве аргумента. В таких случаях this может не ссылаться на исходный объект — оно может быть undefined (в строгом режиме / модулях) или глобальным объектом.
Обычные функции
В обычной функции значение this определяется способом вызова функции. Вот как оно меняется:
- Глобальный контекст: когда функция вызывается без объекта перед точкой,
thisявляется глобальным объектом (windowв браузерах,globalв Node) в нестрогом режиме, иundefined— в строгом режиме или в модулях.
- Методы объекта: когда функция вызывается как метод объекта,
thisссылается на этот объект.
- Обработчики событий: когда обычная функция используется как обработчик события,
thisссылается на элемент, получивший событие.
<button id="myButton">Click me</button>
<p id="output">Click the button to see the result.</p>
<script>
document.getElementById("myButton").addEventListener("click", function () {
document.getElementById("output").innerHTML = "This button was clicked: " + this;
});
</script>Стрелочные функции
Стрелочные функции не имеют собственного this. Вместо этого они захватывают this из окружающего лексического контекста в момент своего определения. Это делает их идеальными для колбэков внутри метода, где нужно сохранить this метода.
- Стабильный контекст в колбэках: полезно, когда
thisдолжен оставаться неизменным внутри колбэка, вложенного в метод.
Здесь logActions использует стрелочную функцию внутри forEach. Стрелочная функция наследует this от logActions, поэтому она корректно ссылается на userProfile.name. Обычная функция, переданная в forEach, получила бы собственный this (глобальный объект или undefined), и this.name не сработало бы.
Не используйте стрелочную функцию для определения метода верхнего уровня объекта, если вы рассчитываете на this. Стрелочная функция не имеет собственного this, поэтому она наследует его из окружающего контекста (часто глобального), а не из объекта — this.name окажется undefined.
Практический пример
Рассмотрим реалистичный пример с объектом, управляющим профилем пользователя в сети, где оба типа функций демонстрируются бок о бок:
Этот пример наглядно показывает, как стрелочные функции помогают сохранить правильный контекст (this), особенно во вложенных колбэках, где динамический this обычной функции молча приводит к ошибкам.
Потеря this и способы её устранения
Классическая ошибка: вы извлекаете метод в переменную или передаёте его как колбэк, и this перестаёт ссылаться на объект.
Когда counter.show извлекается отдельно, при вызове show() перед точкой нет объекта, поэтому this теряется. bind возвращает новую функцию, this которой постоянно зафиксировано. То же самое относится к setTimeout(obj.method, 1000) (не работает) и setTimeout(() => obj.method(), 1000) (работает). Подробнее см. в статье Привязка функций.
Заключение
Методы объекта наделяют данные поведением, а ключевое слово this связывает метод с его объектом. Главное правило: this — это объект перед точкой во время вызова, поэтому его значение может меняться в зависимости от того, как вызвана функция. Обычные функции получают динамический this; стрелочные функции захватывают this лексически — это именно то, что нужно для колбэков, но не подходит для методов верхнего уровня. Когда this теряется, используйте bind, call или apply.
Для дальнейшего изучения рекомендуем ознакомиться со статьями ссылки на объекты и их копирование, функции-конструкторы и new, а также декораторы с call/apply.