Почему вы до сих пор не можете понять цепочку областей видимости JavaScript?

JavaScript
Почему вы до сих пор не можете понять цепочку областей видимости JavaScript?

предисловие

На Nuggets много дискуссий о масштабе и цепочке контекстов, но мало кто объясняет соответствующие механизмы в JS.Здесь я возьму некоторые знания, оставленные большими парнями, и расскажу о подготовке перед пониманием масштаба. Прочитайте статью с этими вопросами:

  • JavaScriptКак он компилируется и выполняется?
  • Как запрашивать слой за слоем при поиске области?
  • JavaScriptКакова природа цепочки областей видимости?

Если вы хотите увидеть анализ напрямую, перейдите к:2. Как выполняется JavaScript?

Существуют также сокращенные формулы:Формула цепочки областей видимости

1. Популярность важнее понимания: принцип компиляции

1.1 Сегментация слов/лексический анализ

Эти блоки кода называются токенами, и эти токены составляют массив потоков токенов.

var sum = 30;
// 词法分析后的结果
[
  "var" : "keyword",
  "sum" : "identifier",
  "="   : "assignment",
  "30"  : "integer",
  ";"   : "eos" (end of statement)
]

1.2 Синтаксический анализ

Преобразует массив потоков токенов в дерево элементов, представляющих синтаксическую структуру программы, которое называется «абстрактным синтаксическим деревом» (Abstract Syntax Tree, короткоAST).

1.3 Генерация кода

Абстрактное синтаксическое дерево (AST) преобразуется в набор машинных инструкций, то есть исполняемый код, который, короче говоря, используется для создания переменной а и сохранения значения 3 в а.

1.4 Различия в процессе компиляции JavaScript

  • JavaScriptВ большинстве случаев компиляция происходит за несколько микросекунд (или даже меньше!) до выполнения кода.
  • JavaScriptДвигатель исчерпал все средства (например,JIT, вы можете отложить компиляцию или даже выполнить перекомпиляцию), чтобы обеспечить наилучшую производительность.

2. Как выполняется JavaScript?

  • Основная мысль: все объявления, включая переменные и функции, обрабатываются перед выполнением любого кода.

  • В момент запуска функции создается рабочий носитель AO (Active Object).

2.1 Пример 1


function a(age) {
    console.log(age);
    var age = 20
    console.log(age);
    function age() {
    }
    console.log(age);
}
a(18);

2.1.1 Фаза анализа

В момент запуска функции создайтеAO (Active Object 活动对象)

АО (активный объект) эквивалентен несущей

AO = {}
Первым шагом является анализ параметров функции:
形式参数:AO.age = undefined
实参:AO.age = 18
Второй шаг — проанализировать объявление переменной:
// 第3行代码有var age
// 但此前第一步中已有AO.age = 18, 有同名属性,不做任何事
即AO.age = 18
Третий шаг — анализ объявления функции:
// 第5行代码有函数age
// 则将function age(){}付给AO.age
AO.age = function age() {}
Особенности объявления функции: если в AO есть атрибут с тем же именем, что и имя функции, эта функция будет перезаписывать его.

Поскольку функция находится в поле JS, она также является типом переменной.

Конечным результатом этапа анализа является:
AO.age = function age() {}

2.1.2 Фаза выполнения

2.2 Пример 2

    function a(age) {
        console.log(age);
        var age = function () {
            console.log('25');
        }
    }
    a(18);

2.2.1 Этап анализа

Первым шагом является анализ параметров функции:
形式参数:AO.age = undefined
实参:AO.age = 18
Второй шаг — проанализировать объявление переменной:
// 第3行代码有函数表达式 var age = function () { console.log('25');}
// 但此前第一步中已有AO.age = 18, 有同名属性,不做任何事
即AO.age = 18
Третий шаг — анализ объявления функции (нет)
Конечным результатом этапа анализа является:
AO.age = 18

2.2.2 Фаза выполнения

2.3 Пример 3

 function a(age) {
        console.log(age);
        var age = function () {
            console.log(age);
        }
        age();
    }
a(18);

2.3.1 Фаза анализа

Первым шагом является анализ параметров функции:AO.age = 18
Второй шаг — проанализировать объявление переменной: есть атрибут с таким именем, ничего не делатьAO.age = 18
Третий шаг — анализ объявления функции (нет)
Конечным результатом этапа анализа является:
AO.age = 18

2.3.2 Фаза выполнения

В этот момент многие люди будут сбиты с толку:age();не должен выводить18?

код выполняется дляage();Фактически, он будет проанализирован и выполнен снова.

2.3.3 age()Анализ и выполнение

// 分析阶段
创建AO对象,AO = {}
第一步,分析函数参数(无)
第二步,分析变量声明(无)
第三步,分析函数声明(无)
分析阶段最终结果是:AO = {}
  • когдаage()мой собственныйAO对象,Прямо сейчасage.AOКогда это пустой объект, он будет вызван.
  • Верхний уровеньAO对象даa,Прямо сейчасa.AO, a.AOСледующий получается после выполненияa.AO.age = function(){console.log(age);}
  • выходƒ () { console.log(age); } `

2.4 Резюме: что такое цепочка областей видимости

Когда каждая функция в JavaScript выполняется, она сначала создает свою собственнуюAOНайдите соответствующее значение атрибута. Если вы не можете его найти, ищите АО родительской функции, и если вы не можете найти его снова, переходите на следующий уровень.AO, пока не будет найден большой босс:window(глобальный охват). И эта статья образовалась "AOцепь" естьJavaScriptв цепочке областей.

3.LHSа такжеRHSЗапрос: два великих оружия цепочки прицелов

Термины LHS и RHS появляются, когда механизм запрашивает переменные. В «Javascript, которого вы не знаете (часть 1)» также есть очень четкое описание. Здесь я хотел бы процитироватьfreecodecampОтвет выше, чтобы объяснить:

LHS = присвоение переменной или запись в память. Думайте об этом как о сохранении текстового файла на жесткий диск. RHS = поиск переменных или чтение из памяти. Думайте об этом как об открытии текстового файла с вашего жесткого диска.Learning Javascript, LHS RHS

3.1 Характеристики обоих

  • будет запрашиваться во всех областях
  • В строгом режиме, когда нужная переменная не найдена, движок выдаетReferenceErrorаномальный.
  • В нестрогом режимеLHRНемного особенного: автоматически создается глобальная переменная
  • При успешном выполнении запроса, если над значением переменной выполняется необоснованная операция, например, выполняется вызов функции для значения нефункционального типа, движок выдает ошибкуTypeErrorаномальный

3.2 Возьмите пример из книги в качестве примера

function foo(a) {
    var b = a;
    return a + b;
}
var c = foo( 2 );

Посмотрите непосредственно на поиск выполнения:

LHS (запись в память):

c=, a=2(隐式变量分配), b=

RHS (чтение памяти):

读foo(2), = a, a ,b
(return a + b 时需要查找a和b)

Лучше понимать по записи/чтению по памяти, чем по книге?

3.3 ОLHSа такжеRHSбросать неправильно

Возьмем два простейших примера:

3.3.1 Неразумная эксплуатация

LHSНа этапе запроса исходный запрос был успешным, ноaВызов функции действияa();, поэтому движок выдаст исключение TypeError.

3.3.2 LHSбросать неправильно

LHSБолее редкая ситуация: много раз мы не включаем строгий режим, то есть:“use strict”. вы можете открыть сейчасchromeИнструменты отладки, попробуйте следующий вывод кода в строгом/нестрогом режиме соответственно:

“use strict”
function init(a){
  b=a+3;
}
init(2);    
console.log(b);

3.3.3 RHSбросать неправильно

4. Формула цепочки содержания

Здесь мы объясняем с картинкой в ​​«Javascript, которого вы не знаете (часть 1)»:

Я также заключилФормула цепочки областей видимости, научим быстро находить вывод:

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

  • В фазе выполнения посмотрите на LR.Если вы не можете найти внешний слой во внутреннем слое, вы не можете найти его, покопавшись в этажах.

Понимание:

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

Сборник авторских статей

Нет публики