Тупо неразличимый механизм работы javascript

JavaScript
Тупо неразличимый механизм работы javascript

При изучении того, как работает javascript, есть несколько концепций, которые всплывают в разных статьях, и их легко спутать. Execution Context (среда выполнения или контекст выполнения), Context Stack (стек выполнения), Variable Object (VO: переменный объект), Active Object (AO: активный объект), LexicalEnvironment (лексическая среда), VariableEnvironment (переменная среда) и т. д., особенно Разница между VO, AO и LexicalEnvironment, VariableEnvironment не освещается во многих статьях. Поэтому я проверил некоторые отечественные и зарубежные статьи и сделал следующие заметки, исходя из собственного понимания. Хотя есть отклонения в понимании из-за его собственных недостатков, я все же считаю, что чтение следующего будет очень полезно для понимания некоторых концепций javascript, таких как продвижение переменных, область действия и закрытие.

1. Среда выполнения и стек выполнения

Чтобы понять механизм работы javascript, вы должны сначала освоить две основные концепции. Контекст выполнения (среда выполнения или контекст выполнения) и стек контекста (стек выполнения)

1. Что такое контекст выполнения (контекст выполнения)

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

    var a = 1;                       // 1.初始化默认进入全局执行环境
    function b() {                   // 3.进入b 的执行环境
        function c() {               // 5. 进入c的执行环境
            ···
        }
        c()                          // 4.在b的执行环境里调用c, 创建c的执行环境
    }
    b()                              // 2. 调用b 创建 b 的执行环境

Классификация сред исполнения:

  • Глобальная среда выполнения: Просто поймите, что программа имеет только один глобальный объект, объект окна, и среда выполнения, в которой находится глобальный объект, является глобальной средой выполнения.
  • Среда выполнения функции: процесс вызова функции создает среду выполнения функции, поэтому каждая программа может иметь бесконечное количество сред выполнения функции.
  • Среда выполнения Eval: среда, специфичная для кода Eval.

2. Как работать в одном потоке (контекстный стек)

Начните с простого примера

function foo(i) {
  if (i < 0) return;
  console.log('begin:' + i);
  foo(i - 1);
  console.log('end:' + i);
}
foo(2);

Как сохранить среду выполнения (глобальную среду выполнения, среду выполнения функции) при выполнении кода? Ответ — стек выполнения. Стек следует принципу "первым пришел - последним вышел". После того, как javascript инициализирует код, он сначала создаст глобальную среду выполнения и поместит ее в текущий стек выполнения. При вызове функции механизм javascript создаст новый среды выполнения и поместите ее в текущее выполнение Верх стека, в новой среде выполнения, если вызов новой функции продолжает происходить, продолжайте создавать новую среду выполнения и поместите ее на вершину текущего стека выполнения до тех пор, пока не будет не является новым вызовом функции. После выполнения верхней функции ее среда выполнения извлекается из текущего стека, а управление передается следующей среде выполнения текущего стека выполнения до глобальной среды выполнения. Когда программа или браузер закрываются, глобальная среда также закрывается и уничтожается.

Итак, вывод:

begin:2
begin:1
begin:0
end:0
end:1
end:2

3. Как создать среду выполнения

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

3.1 Спецификация ES3

Создать этап:

  • 1. Создайте цепочку областей действия.
  • 2. Создать переменный объект ВО (включая параметры, функции, переменные).
  • 3. Определите значение this.

Фаза активации/исполнения:

  • Присвоение переменной выполнено, и код выполняется.
3.2 Спецификация ES5

Создать этап:

  • 1. Определите значение this.
  • 2. Создайте лексическое окружение (LexicalEnvironment).
  • 3. Создайте переменную среду (VariableEnvironment).

Фаза активации/исполнения:

  • Присвоение переменной выполнено, и код выполняется.

Мы можем знать из спецификации, что есть различия между ES3 и ES5 на этапе создания среды выполнения, конечно, они будут определять значение этого на этом этапе. (Мы разберем различные проблемы наведения в специальных статьях в будущем и не будем здесь вдаваться в подробности). Мы сосредоточимся на различиях между этими двумя спецификациями. Хотя от некоторых спецификаций ES3 отказались, освоение процесса создания среды выполнения в ES3 по-прежнему помогает нам понять более глубокие концепции JavaScript.

Два, переменный объект (VO: переменный объект), активный объект (AO: активный объект)

2.1 Основные понятия

VO и AO — это концепции в спецификации ES3.Мы знаем, что переменные объекты будут создаваться на втором этапе процесса создания, то есть VO, который используется для хранения идентификаторов функций, к которым можно получить доступ, но нельзя удалить при выполнении. параметры среды, объявления переменных и т. д., этот объект недоступен в среде js. Отличие АО от ВО в том, что АО — это активированный ВО, не более того.

  • Переменный объект (Variable) объект означает, что в контексте выполнения JS есть объект для хранения идентификаторов функций, формальных параметров, объявлений переменных и т. д., к которым можно получить доступ, но нельзя удалить в контексте выполнения. Они будут привязаны к этому объекту, свойства объекта соответствуют свойствам их моникеров, а значения свойств объекта соответствуют их значениям, но объект является спецификацией или реализацией движка, доступ к которому в среде JS невозможен.

  • Объекты активации имеют переменные объекты для хранения вещей в каждом контексте, но когда к ним можно получить доступ? То есть каждый раз при входе в контекст выполнения активируется переменный объект в контексте выполнения, то есть можно получить доступ к идентификаторам функций, формальным параметрам, объявлениям переменных и т. д. в контексте.

2.2 Детали реализации

Как создать объект VO можно условно разделить на четыре шага.

  • 1. Создайте объект аргументов
  • 2. Просканируйте контекст на наличие объявлений функций (не выражений функций) и для каждой найденной функции создайте атрибут в объекте переменных — в частности, имя функции, — который имеет ссылку на функцию в памяти. Если имя функции уже существует, указатель ссылки будет перезаписан.
  • 3. Просмотрите объявления переменных контекста и для каждого найденного объявления переменной создайте свойство объекта переменной, то есть имя переменной, и инициализируйте значение переменной как неопределенное. Если имя переменной уже существует в объекте переменной, ничего не будет сделано, и сканирование продолжится.

Примечание: Весь процесс можно примерно описать так: Формальные параметры функции => объявление функции => объявление переменной, где при создании объявления функции, если имя существует, оно будет перезаписано, а при создании переменной, если имя имя переменной существует, то Игнорирование ничего не делает.

простой пример

function foo(i) {
    var a = 'hello';
    var b = function privateB() {

    };
    function c() {

    }
}

foo(22);

Псевдокод для выполнения

// 创建阶段
fooExecutionContext = {
    scopeChain: { ... },
    variableObject: {
        arguments: {
            0: 22,
            length: 1
        },
        i: 22,
        c: pointer to function c()
        a: undefined,
        b: undefined
    },
    this: { ... }
}
// 激活阶段
fooExecutionContext = {
    scopeChain: { ... },
    variableObject: {
        arguments: {
            0: 22,
            length: 1
        },
        i: 22,
        c: pointer to function c()
        a: 'hello',
        b: pointer to function privateB()
    },
    this: { ... }
}

Три, LexicalEnvironment (лексическое окружение), VariableEnvironment (переменное окружение)

3.1 Основные понятия

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

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

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

Почему можно отказаться от VO и AO ES3? Лично я думаю, что есть две причины, первая заключается в том, что создание цепочки областей действия и создание объекта переменной (VO), выполняемое в процессе создания, может быть выполнено в процессе создания лексического окружения. Второй — для привязки объявлений и переменных функций хранения (let и const) и переменных хранения (var) в es6, которые можно различить по двум разным процессам (лексическое окружение, переменное окружение).

3.2 Лексическое окружение (lexicalEnvironment)

Лексическое окружение состоит из двух частей

  • запись среды, в которой хранятся объявления переменных и функций
  • Ссылка на внешнюю среду (внешнюю), через которую можно получить доступ к внешней лексической среде

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

Экологический отчет состоит из двух частей.

  • Декларативные записи окружения (декларативные записи окружения): хранят переменные, функции и параметры, но в основном используются для функций и захвата лексических окружений. Примечание. Значение аргументов хранится в среде функции. Подробный процесс может относиться к деталям реализации VO, которые в основном одинаковы.
  • записи объектной среды, в основном используемые для с и глобальных лексических сред

Псевдокод выглядит следующим образом

// 全局环境
GlobalExectionContext = {  
// 词法环境
  LexicalEnvironment: {  
    EnvironmentRecord: {  
    
        ···
    }
    outer: <null>  
  }  
}
// 函数环境
FunctionExectionContext = {  
// 词法环境
  LexicalEnvironment: {  
    EnvironmentRecord: {  
        // 包含argument
        
    }
    outer: <Global or outer function environment reference>  
  }  
}

3.3 Переменная среда (objectEnvironment)

Среда переменных также является лексической средой, основное отличие состоит в том, что lexicalEnviroment используется для хранения объявлений функций и привязок переменных ( let и const ), а ObjectEnviroment используется только для хранения привязок переменных ( var ).

3.4 Отображение псевдокода

Весь процесс создания по спецификации ES5 может относиться к приведенному ниже псевдокоду.

let a = 20;  
const b = 30;  
var c;

function d(e, f) {  
 var g = 20;  
 return e * f * g;  
}

c = d(20, 30);
// 全局环境
GlobalExectionContext = {

  this: <Global Object>,
    // 词法环境
  LexicalEnvironment: {  
    EnvironmentRecord: {  
      Type: "Object",  // 环境记录分类: 对象环境记录
      a: < uninitialized >,  // 未初始化
      b: < uninitialized >,  
      d: < func >  
    }  
    outer: <null>  
  },

  VariableEnvironment: {  
    EnvironmentRecord: {  
      Type: "Object",  // 环境记录分类: 对象环境记录
      c: undefined,  // undefined
    }  
    outer: <null>  
  }  
}
// 函数环境
FunctionExectionContext = {  
   
  this: <Global Object>,

  LexicalEnvironment: {  
    EnvironmentRecord: {  
      Type: "Declarative",  // 环境记录分类: 声明环境记录
      Arguments: {0: 20, 1: 30, length: 2},  // 函数环境下,环境记录比全局环境下的环境记录多了argument对象
    },  
    outer: <GlobalLexicalEnvironment>  
  },

  VariableEnvironment: {  
    EnvironmentRecord: {  
      Type: "Declarative",  // 环境记录分类: 声明环境记录
      g: undefined  
    },  
    outer: <GlobalLexicalEnvironment>  
  }  
}

В-четвертых, цепочка объемов

В предыдущем процессе создания мы оставили предзнаменование: в спецификации ES3 есть процесс создания цепочки областей видимости, а в ES5, в процессе создания лексического окружения или переменного окружения, есть еще и процесс генерации ссылки на Внешняя среда. Так что же делает этот процесс? Проиллюстрируем на простом примере.

function one() {

    var a = 1;
    two();

    function two() {

        var b = 2;
        three();

        function three() {

            var c = 3;
            alert(a + b + c); // 6

        }

    }

}

one();

Когда выполняемая среда из трех выполняется, ни A NOL B не находятся в переменных C, поэтому цепочка охвата зависит от приложения к переменным внешней среды выполнения. Цепочка охвата, созданная в ES3, показана на рисунке:

Когда интерпретатор выполняет alert(a + b + c), он сначала выясняет, есть ли переменная a в его собственной среде выполнения. цепочка масштабов. Он проверяет, существует ли a внутри, и, если не может его найти, ищет предыдущую среду выполнения по цепочке областей видимости, пока не найдет ее, или в глобальную область верхнего уровня. Точно так же можно анализировать и спецификацию ES6.

Итак, это вводит важную концепцию в javascript, замыкания. Из приведенного выше объяснения среды выполнения мы можем понять, что замыкание — это переменная, к которой внутренняя среда обращается к среде верхнего уровня через цепочку областей видимости. Следовательно, также существует проблема, заключающаяся в том, что невозможно выполнить восстановление переменной.Пока существует цепочка областей видимости функции, значение переменной не может быть восстановлено из-за замыкания.

Примечание. Цепочка областей действия этой цепочки областей действия и цепочка прототипов — это не одно и то же.

Пять, резюме

Благодаря знакомству с операционным механизмом javascript у меня появилось более глубокое понимание некоторых продвинутых концепций javasript, особенно разницы между некоторыми концепциями в тумане. При разных спецификациях интерпретация разных концепций более способствует глубокому изучению основных идей выполнения javascript. Я считаю, что это самый важный шаг в понимании языка javascipt.

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

Данная статья является оригинальной статьей блогера, просьба указывать источник для перепечаткиnuggets.capable/post/684490…