Глубокое понимание предварительных знаний о закрытии → объем и лексический объем

внешний интерфейс переводчик JavaScript

предисловие

Последние два дня я как раз обсуждал с друзьями замыкания, "божественного зверя" в JavaScript. Многие студенты подумают, что замыкания слишком надоедливы, и не поймут, почему... На самом деле, я был таким, когда впервые вступил в контакт с JavaScript.

Тем не менее, закрытие очень важно! Очень важно! Очень важно! В «JavaScript, которого вы не знаете» даже написано «Для тех, кто имеет небольшой опыт работы с JavaScript, но никогда не понимал концепции замыканий, понимание замыканий можно рассматривать как ощущение возрождения.".

Итак, увидев это, вы хотите узнать больше о замыканиях? Не торопитесь, не торопитесь, есть очень важное предварительное знание для настоящего понимания замыкания, т.Объем и лексический объем, если вы плохо понимаете лексическую область видимости, то замыкания точно ее не понимают! Итак, давайте внимательно посмотрим на лексическую область видимости.

сфера

Сначала выбросим понятие: "Лексическая область видимости — это рабочая модель области видимости.", независимо от глубокого смысла этого предложения, но с поверхности, мы должны быть в состоянии сделать вывод, что нет понятия лексического объема без понятия объема. Итак... Далее, вы поняли...

что такое объем

Одним словом, "Область видимости — это набор правил, определяющих, где и как искать переменные (идентификаторы), прочитайте ключевой момент в этом предложениипеременная поиска (идентификатор), тогда начнем с поиска переменных.

Давайте посмотрим на кусок простого кода

function foo() {
	var a = 'iceman';
	console.log(a); // 输出"iceman"
}
foo();

Когда функция foo выполняется, выводится переменная a, так откуда же берется переменная a, я видел, что в первой строке функции есть код, определяющий переменную avar a = 'iceman'.

Взгляните еще раз на тот же простой код

var b = 'programmer';
function foo() {
	console.log(b); // 输出"programmer"
}
foo();

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

Обратите внимание, что в приведенных выше двух фрагментах кода есть переменные поиска, первый фрагмент кода находится вфункциянайдите переменную в , второй фрагмент кода находится вГлобальныйнайти переменную b в . А теперь закройте глаза, я добавлю несколько слов к словам, выделенным жирным шрифтом!

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

Итак, вы понимаете? С точки зрения непрофессионала,Область видимости — это место, где вы ищете переменные.. Если переменная найдена в функции, можно сказать, что переменная найдена в области видимости функции; если переменная найдена в глобальной области, можно сказать, что переменная найдена в глобальной области видимости!

Не знаю, заметили ли ваши одноклассники одну деталь.Когда мы ищем переменную b, мы сначала ищем в области видимости функции, а если не находим, то ищем в глобальной области видимости.Идет процесс поиска внешнего слоя. Мы как бы ищем переменные снизу вверх по цепочке.Эту цепочку мы называемцепочка прицелов.

вложение области видимости

Перед let и const в ES6 есть только область действия и глобальная область действия.Область действия функции должна быть в глобальной области видимости, и область действия функции может продолжать быть вложенной в область действия функции, как показано на рисунке:

作用域嵌套.png

Выразить в коде:

作用域嵌套.png

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

Правила поиска для переменных (идентификаторов) в области видимости

Прежде всего, позвольте мне сказать, что в JavaScript есть процесс компиляции, не удивляйтесь, он есть! то естьvar name = 'iceman'Этот код на самом деле имеет два действия:

  • Компилятор объявляет имя переменной в текущей области

  • Механизм выполнения ищет переменную в области видимости, находит переменную имени и присваивает ей значение.

Докажите приведенное выше утверждение:

console.log(name); // 输出undefined
var name = 'iceman'; 

существуетvar name = 'iceman'Предыдущая строка выводит переменную имени, и об ошибке не сообщается.Вывод не определен, что указывает на то, что переменная уже существует, когда она выводится, но ей не присвоено значение.

На самом деле компилятор работает так: он компилирует сверху вниз перед выполнением кода, встречая переменную, объявленную с помощью var, он сначала проверяет, существует ли эта переменная в текущей области видимости. Если она существует, это объявление игнорируется; если она не существует, переменная объявляется в текущей области видимости.

Приведенный выше простой код содержит два типа поиска: тип поиска при выводе значения переменной — RHS, а тип поиска, когда переменной присвоено значение, — LHS.

Думаю, вы можете догадаться, что означают буквы "L" и "R". Левая и правая стороны здесь относятся к левой и правой сторонам операции присваивания. То есть запросы LHS выполняются, когда переменные появляются в левой части операции присваивания, а запросы RHS выполняются, когда они появляются в правой части.

Говоря простым языком, RHS должен получить исходное значение.

Уведомление: "Левая и правая часть присваивания" не означает просто "=", на самом деле существует несколько форм присваивания.

Переменные поиска в области все RHS, и правило поиска состоит в том, чтобы начать с текущей области, Если она не найдена, то перейти к родительской области, чтобы найти ее, и искать ее слой за слоем, если это не так. найден в глобальной области видимости. , он сообщит об ошибке:ReferenceError: переменная не определена

Переменная поиска во всех операциях присваивания — LHS. вa=4Этот тип операции присваивания также будет искаться в текущей области видимости.Если она не найдена, она будет искаться во внешней области видимости.Если глобальная переменная найдена, глобальная переменная a будет создана в нестрогом режиме. Однако делать это не рекомендуется, так как это загрязняет глобальные переменные при легком, а в худшем случае вызывает утечки памяти (например: a = очень большой массив, a всегда ссылается на глобальные переменные, и программа не будет автоматически уничтожать это).

лексический охват

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

Ранее мы выдвинули концепцию: "Лексическая область видимости — это рабочая модель области видимости". Есть две рабочие модели области видимости. Лексическая область видимости в JavaScript является более распространенной, а другая — динамической областью видимости. используется меньше языков).

Так называемая лексическая областьОбласть видимости переменных и блоков определяется при написании кода, то есть лексическая область видимости — это статическая область видимости, которая определяется при написании кода..

См. следующий код:

function fn1(x) {
	var y = x + 4;
	function fn2(z) {
		console.log(x, y, z);
	}
	fn2(y * 5);
}
fn1(6); // 6 10 50

В этом примере есть три вложенных области видимости, как показано на рисунке:

image.png

  • A является глобальной областью и имеет идентификатор: fn1

  • B — это область, созданная fn1, с тремя идентификаторами: x, y, fn2.

  • C — это область, созданная fn2, с идентификатором: z

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

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

Примечание 1: eval() и with можно использовать для «обмана» лексической области видимости из-за их специфичности, но в нормальных условиях их использование не рекомендуется, так как это вызовет проблемы с производительностью.

Заметка 2: В ES6 let и const имеют область действия на уровне блоков, которая будет представлена ​​позже.

обращать внимание

Вы можете обратить внимание на мой паблик: icemanFE, и продолжать обновлять технические статьи!

公众号.png