Разница между контекстом (context) и областью видимости (scope) в JavaScript

Разница между контекстом (context) и областью видимости (scope) в JavaScript

Maksym Pohribniak

Спрашивая данный вопрос на собеседованиях, начинающие и даже некоторые опытные разработчики путают эти, казалось бы, базовые понятия.

Scope – область видимости

Область видимости определяет, есть ли у вас доступ к переменной.

До введения let и const область видимости в JavaScript определялась функцией (у var функциональная область видимости). Переменные объявленные вне функции записывались в глобальную область видимости.

var a = 'global';

function localA() {
var a = 'local'
}
localA();

console.log(a) // 'global'
console.log(window.a) // 'global'

В данном примере мы создали 2 переменные a и функцию localA.
Переменная a со значением global объявлена вне функции, она доступна как свойство объекта window. Собственно, после вызова функции localA, значение переменной a не изменилось. Функция localA создает собственную область видимости, и переменные объявленные внутри данной функции (как и любой другой) доступны только в ней же (и во вложенных функциях) и не доступны для чтения или изменения снаружи. При этом локальные переменные имеют больший приоритет, чем глобальные.

Перепишем данный пример следующим образом:

var a = 'global';

function localA() {
a = 'local'
}
localA();

console.log(a) // 'local'
console.log(window.a) // 'local'

Внутри функции localA мы убрали ключевое слово var. Таким образом, обращаясь из данной функции, мы имеем дело с глобальной переменной а.
Исходя их выше описанного, её значение заменяется на 'local'.

let и const

С помощью этих ключевых слов мы можем создавать переменные с блочной областью видимости.

if (false){
let a = 'local';
}
console.log(a); // Uncaught ReferenceError: a is not defined ...

Блочная область видимости похожа на функциональную, но она ограничена не функцией, а блоком кода ( { } ).  Это означает, что переменные ограничены блоком, в котором они используются, неважно будет ли это блок if, блок for, или функция и не будут просачиваться в глобальную область видимости.

Context – контекст выполнения (this)

Контекст описывает окружение в котором выполняется код (любой код имеет контекст выполнения). В каждый момент времени только один контекст выполнения выполняет код. Несколько популярных видов контекста:

  • Global контекст
  • Function контекст
  • Стрелочные функции
  • В методе объекта
  • В конструкторе
  • В методах call, apply и bind

В браузере:

  • Как обработчик событий DOM
  • В инлайновом обработчике событий

Одна и та же функция может быть вызвана с разным контекстом.

Контекстом еще часто называют значение переменной this внутри функции.  Значение переменной this чаще всего определяется тем, как вызывается функция.

function fn() {
console.log(this);
}
const user = {
method: fn
}

fn(); // window
user.method(); // user
fn.call({ foo: 'bar' }) // { foo: 'bar' }

В примере выше мы вызвали одну и ту же функцию в разных контекстах:

  • как функцию
  • как метод объекта
  • специальным методом привязывающим контекст call (apply, bind)

При этом мы получили разные контексты.

В ES6 добавился еще один вид функций (стрелочные функции () => {}), которые обладают лексическим контекстом (не привязаны к собственному thisargumentssuper, или new.target).


Понимание области видимости и контекста важно для понимания работы замыканий, функций обратного вызова, частичного применения функций и других важных концепций JavaScript.


Спасибо за внимание!



Report Page