При изучении того, как работает 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.
Использованная литература:
- stackoverflow.com/questions/2…
- Дэвид what-riff.com/blog/what-i…
- Дэвид riff.com/blog/Java удаляет…
- GitHub.com/read-share/have-he…
- сегмент fault.com/ah/119000000…
Данная статья является оригинальной статьей блогера, просьба указывать источник для перепечаткиnuggets.capable/post/684490…