Skip to Content
JavaScriptthis и прототипы

this и прототипы

Уровень: middle.

Вопрос

От чего зависит this и чем прототип отличается от класса?

Короткий ответ

this определяется способом вызова, а не местом объявления функции.

  • Вызов как метод, obj.method(), — this равен obj.
  • Обычный вызов fn() — в строгом режиме this равен undefined, без него указывает на глобальный объект.
  • call, apply и bind задают this явно. bind возвращает новую функцию.
  • Стрелочная функция не имеет своего this и берёт его из внешнего лексического окружения.
  • new создаёт объект и подставляет его как this.

Прототип — это объект, на который ссылается [[Prototype]]. Поиск свойства идёт по цепочке, пока не найдётся поле или не кончится цепочка. class — синтаксис над той же моделью: методы лежат на Constructor.prototype, статические — на самой функции.

Разбор

Метод, переданный колбэком, теряет получателя:

const user = { name: 'Ann', hi() { return this.name }, } setTimeout(user.hi, 0) // this больше не user

Чинится стрелкой-обёрткой или bind. Стрелочный метод в литерале объекта как раз не подойдёт, если нужен this объекта: у стрелки своего this нет.

obj.hasOwnProperty и Object.hasOwn(obj, key) смотрят только собственные поля. 'toString' in obj может быть истинным из-за прототипа. На собеседовании это связывают с перебором for...in, который идёт и по перечисляемым унаследованным ключам.

На что смотрят на senior

Длинная цепочка прототипов и частые промахи по свойствам стоят дороже, чем один собственный объект, но в прикладном UI это редко узкое место. Важнее не мутировать Object.prototype: вы добавите поле всем объектам и сломаете чужие переборы.

Композиция (функция принимает объект и возвращает поведение) часто читается проще, чем иерархия из четырёх классов. Класс уместен, когда есть инварианты экземпляра и понятный жизненный цикл.

Типичные ошибки

  • Путать this со замыканием. Замыкание помнит переменные, this зависит от вызова.
  • Считать, что стрелка «всегда берёт компонент». Она берёт this того места, где написана.
  • Думать, что class создаёт другую объектную модель, отдельную от прототипов.

Задача

Чему равен this в каждом вызове?

const user = { name: 'Ann', hi() { return this.name }, hiArrow: () => this.name, } const hi = user.hi user.hi() hi()
Показать ответ

user.hi() берёт this из вызова через точку: 'Ann'.

hi() — вызов без базы. В строгом режиме this будет undefined, чтение name упадёт. В нестрогом this станет глобальным объектом.

hiArrow — стрелка. Своего this у неё нет, она возьмёт this снаружи объекта, не user.

Last updated on