Разница между контекстом (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 добавился еще один вид функций (стрелочные функции () => {}), которые обладают лексическим контекстом (не привязаны к собственному this, arguments, super, или new.target).
Понимание области видимости и контекста важно для понимания работы замыканий, функций обратного вызова, частичного применения функций и других важных концепций JavaScript.
Спасибо за внимание!