webroad.online
  1. 1Веб
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Инструменты
  8. 8React
  9. 9Стейт-менеджмент
  10. 10Next.js
  11. 11Формы
  12. 12Данные и бэкенд
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Анимации
  16. 16Тестирование
  17. 17Архитектура
JavaScript · Урок 4 из 17

Область видимости, hoisting и this

Где живут переменные и почему метод «теряет» this.

Обновлено

Что такое область видимости

Область видимости (scope) = часть кода, где переменная существует и может использоваться. За её пределами переменной нет.

function order() {
  const total = 100      // существует только внутри order()
}
console.log(total)       // ✗ ReferenceError

Зачем это нужно: без областей видимости все переменные были бы глобальными и мешали бы друг другу (две функции, у каждой свой i).

Виды областей видимости

Вид Создаётся Содержит
глобальная файлом / страницей всё, что объявлено вне функций (в ES-модулях — глобально только для модуля)
функции каждой функцией её параметры и переменные (включая var)
блока любыми { }: if, for, while, просто {} let, const, class
const app = 'learn'            // глобальная (для модуля)

function render() {
  const title = 'Функции'      // область функции
  if (title) {
    const upper = title.toUpperCase()   // область блока
  }
  upper                        // ✗ уже не существует
}

Лексическая область и цепочка областей

Когда вы используете переменную, JS ищет её в текущей области, затем в родительской, затем в её родителе… до глобальной. Эта цепочка называется scope chain.

Важно: родитель определяется тем, где функция написана в коде (лексически), а не тем, откуда она вызвана.

const x = 'global'

function outer() {
  const x = 'outer'
  return function inner() { return x }   // inner написана внутри outer → видит x из outer
}

outer()()   // 'outer'

Отсюда берётся замыкание — см. Функции.

Что такое hoisting

Hoisting («поднятие») = перед выполнением кода JS проходит по области видимости и регистрирует все объявления. Эффект: некоторые вещи можно использовать до строки, где они написаны.

Каждый вид объявления поднимается по-своему:

Объявление Поднимается? Что получите, если использовать до его строки
function f() {} да, вместе с телом функция работает нормально
var x = 1 да, но без значения undefined
let / const да, но заблокировано ReferenceError (TDZ)
class A {} да, но заблокировано ReferenceError
const f = () => {} как любой const ReferenceError
sayHi()                  // ✓ 'Привет' — объявление функции поднято целиком
function sayHi() { return 'Привет' }

console.log(a)           // undefined — var поднят, значение появится только на его строке
var a = 1

console.log(b)           // ✗ ReferenceError
const b = 2

TDZ — временная мёртвая зона

Между началом области и строкой, где объявлен let/const, переменная находится в «мёртвой зоне» (TDZ): JS знает, что она есть, но не даёт её использовать. Это хорошо — ловятся баги, которые var прятал за undefined.

Что это значит на практике: можно организовать файл с главной функцией сверху и вспомогательными (объявления function) снизу — это работает благодаря hoisting.

Что такое this

this — особая переменная внутри функций, которая указывает на объект, в контексте которого выполняется функция. В отличие от остальных переменных, значение this зависит не от того, где функция написана, а от того, как она вызвана.

Правила в порядке приоритета

Как вызвать this — это Пример
new Fn() новый созданный объект new User('Ana')
fn.call(obj), fn.apply(obj), fn.bind(obj) obj, задан явно greet.call(user)
obj.method() объект перед точкой user.greet()
просто fn() undefined (в модулях / strict mode) const g = user.greet; g()
стрелочная функция this того места, где она написана, — своего this нет () => this.name
const user = {
  name: 'Ana',
  greet() { return `Привет, ${this.name}` },
}

user.greet()             // 'Привет, Ana' — this = user

const greet = user.greet
greet()                  // ✗ this равен undefined — метод «оторвали» от объекта

const bound = user.greet.bind(user)
bound()                  // ✓ 'Привет, Ana'

Почему стрелочные функции «чинят» колбэки

const timer = {
  seconds: 0,
  start() {
    setInterval(function () { this.seconds++ }, 1000)  // ✗ this — не timer
    setInterval(() => { this.seconds++ }, 1000)        // ✓ стрелочная берёт this из start()
  },
}

Когда this важен на практике

  • В современном React (функции + хуки) — почти никогда.
  • В классах (свои ошибки, SDK), в классических обработчиках событий и в старом коде.
  • Правило: методы → обычные функции; колбэки внутри них → стрелочные; передаёте метод как колбэк → bind или () => obj.method().

Коротко

  • Область видимости = где живёт переменная: глобальная, функции, блока. Поиск поднимается по цепочке областей — по месту, где написан код.
  • Hoisting = объявления регистрируются до выполнения; функции работают до определения, let/const дают ошибку (TDZ).
  • this зависит от того, как вызвана функция; у стрелочных функций нет своего this.

Официальные источники

Упражнения

Была ли страница полезной?

Один клик — без регистрации.