Что такое объем?

Область действия - это способ поиска переменной с заданным именем. Переменная имеет область действия, которая представляет собой всю область, в которой к этой переменной можно получить доступ по имени.

В Javascript мы можем вызвать Scope как набор правил, которые определяют, как Engine может искать переменную по ее имени идентификатора и находить ее.

Существует два типа моделей Scope, которые широко используются. Безусловно, наиболее часто используемой моделью Scope в подавляющем большинстве языков программирования является Lexical Scope, также Javascript использует эту модель Lexical Scope . Другая модель, которая все еще используется некоторыми языками, такими как сценарии Bash, называется Dynamic Scope. Теперь мы обсудим, что это за модели Scope? Тогда мы поймем разницу между ними.

Динамический объем

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

Что такое стек вызовов?

Стек вызовов - это механизм, с помощью которого интерпретатор отслеживает свое место в сценарии, вызывающем несколько функций: какая функция выполняется в данный момент, какие функции вызываются изнутри этой функции и т. д. Структура данных стека - это LIFO, означает «последний пришел - первым ушел». Давайте разберемся на примере из MDN:

function greeting() {
   // [1] Some codes here
   sayHi();
   // [2] Some codes here
}
function sayHi() {
   return "Hi!";
}

// Invoke the `greeting` function
greeting();

// [3] Some codes here
  1. Игнорировать все функции, пока не дойдет до вызова функции приветствия ().
  2. Добавьте функцию приветствия () в список стека вызовов.
  3. Выполнить все строки кода внутри функции приветствия ().
  4. Перейти к вызову функции sayHi ().
  5. Добавьте функцию sayHi () в список стека вызовов.
  6. Выполнить все строки кода внутри функции sayHi () до ее конца.
  7. Вернуть выполнение к строке, которая вызвала sayHi (), и продолжить выполнение остальной части функции приветствия ().
  8. Удалите функцию sayHi () из нашего списка стека вызовов.
  9. Когда все, что находится внутри функции приветствия (), было выполнено, вернитесь к ее вызывающей строке, чтобы продолжить выполнение остальной части кода Javascript.
  10. Удалите функцию welcome () из списка стека вызовов.

Это все краткое описание того, как работает стек вызовов и что он делает.

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

Что такое время автора?

Это время, когда разработчик пишет код. Это может означать, восприятие программы, как вы ее видите перед компиляцией.

Динамическая область видимости не имеет отношения к тому, как и где объявляются функции и области действия, а скорее к тому, откуда они вызываются. Это означает, что цепочка областей видимости основана на стеке вызовов, а не на вложении областей в код.

Давайте разберемся с динамической областью видимости на примере из книги Кайла Симпсона - вы не знаете JS, Scope & Closure:

Предположим, что если Javascript имеет динамическую область видимости, при выполнении foo () теоретически приведенный ниже код даст результат 3, но как?

function foo() {
	console.log( a ); // 3  (not 2!)
}

function bar() {
	var a = 3;
	foo();
}

var a = 2;

bar();

Когда foo () не может разрешить ссылку на переменную для a, вместо увеличения вложенной (лексической области - мы скоро упомянем) цепочки областей видимости, она переходит к call-stack, чтобы узнать, откуда был вызван foo (). Поскольку foo () был вызван из bar (), он проверяет переменные в области видимости для bar () и находит там a со значением 3 .

Чтобы было ясно, Javascript не имеет динамической области видимости. Он имеет лексическую область видимости. Но обратите внимание, что этот механизм похож на динамическую область видимости.

Давайте углубимся в лексическую область видимости.

Лексическая область видимости

Лексическая область видимости - это область, которая определяется во время лексирования. Другими словами, лексическая область видимости основана на том, где переменные и блоки области видимости создаются вами во время записи, и, таким образом, устанавливается в камне к тому времени, когда лексер обрабатывает ваш код.

Его также называют статической областью действия. В языке с лексической областью видимости идентификатор привязан к некоторой области исходного кода, содержащей объявление идентификатора. Это означает, что идентификатор доступен только в этом регионе.

PS: Есть несколько способов обмануть лексическую область видимости, например, с помощью ‘with’ и ‘eval ()’. Но это не предлагается и больше не должно использоваться в вашем коде. Эта часть здесь будет пропущена и упоминаться не будет. Вы можете найти больше информации об этом в книге Кайла Симпсона - Вы не знаете JS, Scope & Closures.

Давайте объясним, как работает лексическая область, на примере из книги Кайла Симпсона:

function foo(a) {

	var b = a * 2;

	function bar(c) {
		console.log( a, b, c );
	}

	bar(b * 3);
}

foo( 2 ); // 2 4 12

В этом примере кода есть три вложенных области видимости. Может быть полезно думать об этих объемах как о пузырях друг в друге.

  • Пузырь 1 охватывает глобальную область и имеет только один идентификатор: foo.
  • Пузырь 2 охватывает область foo, которая включает три идентификатора: a, bar, b.
  • Пузырь 3 охватывает область bar и включает только один идентификатор: c.

Пузырьки области видимости определяются тем, где записаны блоки области видимости, какой из них вложен внутри другого и т. Д. Обратите внимание, что эти вложенные пузыри строго вложены.

Как система выполняет поиск?

В приведенном выше фрагменте кода Engine выполняет оператор console.log (…) и ищет три упомянутые переменные a, b, и c . Он начинается с самого внутреннего пузыря области видимости, пузыря 3. Он не найдет там a, поэтому поднимется на один уровень вверх до следующего ближайшего пузыря осциллографа, пузыря 2. Он находит там a и поэтому использует этот a. То же самое для b. Но c, он находится внутри bar (…), Bubble 3.

Переменная c находится внутри bar (…) и внутри foo (…), console.log (…) нашел бы и использовал оператор в bar (…), никогда не дойдя до оператора в foo (…).

Поиск области прекращается, как только обнаруживается первое совпадение. Одно и то же имя идентификатора может быть указано на нескольких уровнях вложенной области, что называется затенением (внутренний идентификатор затеняет внешний идентификатор) . Поиск в области видимости всегда начинается с самой внутренней области, которая выполняется в данный момент, и продвигается наружу / вверх до первого совпадения и остановки.

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

Основное различие между лексической и динамической областью видимости: лексическая область видимости - это время записи, а динамическая область - время выполнения. Лексическая область видимости заботится о том, где была объявлена ​​функция, но динамическая область видимости заботится о том, откуда функция была вызвана.

использованная литература