0 3.6K ru

Объяснение Scope (Chain) в JavaScript с помощью визуализации

Categories: 💻 Programming

Это перевод статьи Лидии Холли, где она разбирает такое понятие как Scope (Chain) с помощью визуализации.

Давайте рассмотрим следующий код:

const name = "Lydia"
const age = 21
const city = "San Francisco"

function getPersonInfo() {
  const name = "Sarah"
  const age = 22

  return `${name} is ${age} and lives in ${city}`
}

console.log(getPersonInfo())

В коде мы вызываем функцию getPersonInfo, которая возвращает строку, содержащую значения переменных nameage и city:
Sarah is 22 and lives in San Francisco. Но функция getPersonInfo не содержит переменную city 🤨 Как функция смогла получить значение переменной city?

Во-первых, пространство памяти настраивается для разных контекстов. По умолчанию global context(window в браузере, global в ноде) и local context для вызванной функции getPersonInfo. У каждого контекста также есть цепочка областей видимости (scope chain).

Для функции getPersonInfo цепочка областей видимости (scope chain) выглядит так:

scope

Scope chain в основном представляет собой «цепочку ссылок» на объекты, которые содержат ссылки на значения и другие скоупы, на которые можно ссылаться в этом контексте выполнения. Scope chain создается при создании контекста выполнения, то есть создается в runtime.

Однако давайте сосредоточимся на scope. В следующих примерах пары key/value в контекстах выполнения представляют ссылки, которые в scope как переменные.

variable

Scope chain глобального контекста выполнения содержит ссылку на 3 переменные: name с значением Lydiaage с значением 21, и city с значением San Francisco. В local context ссылки на 2 переменные: name с значением Sarah и age с значением 22.

Пытаясь получить доступ к переменным в функции getPersonInfo, движок сначала проверяет цепочку локального скоупа.

local scope

В локальном scope chain содержиться ссылка на name и age. У переменной name значение Sarah и у переменной age значение 22. Но что происходит когда мы пытаемся доступиться до city?

Для того чтобы найти значение переменной city, движок «спускается вниз по цепочке». В этом кейсе он ищет переменную города в внешнем скоупе, на который ссылается локальный скоуп.

city

Мы можем спуститься по scope chain, но не можем подняться вверх по цепочке. (Хорошо, это может сбивать с толку, потому что некоторые люди говорят «вверх», а не «вниз», поэтому я просто перефразирую: вы можете перейти к внешним scope, но не к "более внутренним скоупам". Это можно визуализировать как водопад:

waterfall

Или даже глубже:

scope global

Возьмем этот код в качестве примера.

code

Это почти то же самое, но есть одно большое отличие: теперь мы объявили city только в функции getPersonInfo, а не в global scope. Мы не вызывали функцию getPersonInfo, поэтому локальный контекст тоже не создается. Теперь давайте запросим доступ к значениям имени, возраста и города в глобальном контексте.

context

Эта попытка выдаст ошибку ReferenceError! Не удалось найти ссылку на переменную с именем city в глобальной области видимости, и не было других скоупов для поиска, и она не может подняться по цепочке областей видимости.

Таким образом, можно использовать область видимости как способ «защитить» свои переменные и повторно использовать имена переменных.

Помимо глобальной и локальной областей, существует также block scope. Переменные, объявленные с помощью ключевого слова let или const, ограничены ближайшими фигурными скобками ({}).

const age = 21

function checkAge() {
  if (age < 21) {
    const message = "You cannot drink!"
    return message
  } else {
    const message = "You can drink!"
    return message
  }
} 

Это можно визуализировать следующим образом:

block

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

Итог:

  1. Вы можете рассматривать "scope chain" как цепочку ссылок на значения, к которым мы можем получить доступ в текущем контексте.
  2. Scopes также позволяют повторно использовать имена переменных, которые определены ниже по scope chain, поскольку она может идти только вниз по цепочке областей видимости, но не вверх.

Comments:

Please log in to be able add comments.