предисловие
Внезапно я чувствую, что для разработчика JavaScript, мне нужно знать, как программа JavaScript работает внутри, поэтому очень важно понимать контекст выполнения и стек выполнения в этой главе, а также для понимания других концепций JavaScript (оттенки переменных, объем и закрытие)) полезны.
Я прочитал много связанных статей, хорошо написанных, обобщил описание ES3 и ES6 контекста реализации концепции, а также представил новые концепции.
что такое контекст выполнения
Проще говоря, контекст выполнения — это абстракция среды, в которой оценивается и выполняется код JavaScript. Всякий раз, когда код Javascript выполняется, он выполняется в контексте выполнения.
тип контекста выполнения
В JavaScript существует три типа контекста выполнения.
-
глобальный контекст выполнения— Это контекст по умолчанию или базовый, любой код не внутри функции находится в глобальном контексте. Он делает две вещи: создает глобальный объект окна (в случае браузера) и устанавливает
thisЗначение равно этому глобальному объекту. В программе существует только один глобальный контекст выполнения. - контекст выполнения функции— Всякий раз, когда вызывается функция, для этой функции создается новый контекст. Каждая функция имеет свой собственный контекст выполнения, но создается при вызове функции. Контекстов функций может быть любое количество. Всякий раз, когда создается новый контекст выполнения, он выполняет серию шагов в определенном порядке (обсуждается позже).
-
Контекст выполнения функции Eval- выполнить на
evalКод внутри функции также будет иметь свой контекст выполнения, но поскольку разработчики JavaScript не часто используютeval, поэтому я не буду обсуждать это здесь.
Содержимое контекста выполнения ES3
Контекст выполнения — это абстрактное понятие, мы можем понимать его какobject, контекст выполнения включает следующее:
- переменный объект VO
- Активный объект АО
- цепочка прицелов
- информация о вызывающем абоненте это
Переменный объект (variable objectкороткое имяVO)
Каждый контекст выполнения имеет объект, представляющий переменную -переменный объект, переменный объект глобальной среды выполнения всегда существует, а переменная локальной среды, такая как функция, будет существовать только во время выполнения функции.Когда функция вызывается и до запуска кода конкретной функции, механизм JS будет использовать текущую функциюсписок параметров(arguments) инициализирует «переменный объект» и связывает с ним текущий контекст выполнения, объявленный в блоке функционального кодаПеременнаяа такжефункциябудет добавлен как свойство к этому объекту переменной.
有一点需要注意,只有函数声明(function declaration)会被加入到变量对象中,而函数表达式(function expression)会被忽略。
// 这种叫做函数声明,会被加入变量对象
function demo () {}
// tmp 是变量声明,也会被加入变量对象,但是作为一个函数表达式 demo2 不会被加入变量对象
var tmp = function demo2 () {}
Объекты-переменные в глобальном контексте выполнения и в контексте выполнения функции также немного отличаются, разница между ними просто:
-
Переменный объект в глобальном контексте является глобальным объектом, в среде браузера это
windowобъект. -
Свойства, определенные внутри объекта переменной в контексте выполнения функции, нельзя получить доступ напрямую, только при вызове функции переменный объект (
VO) активируется как активный объект (AO), мы можем получить доступ к его свойствам и методам.
Активный объект (activation objectкороткое имяAO)
Когда функция переходит в стадию выполнения, переменный объект, к которому нет доступа, активируется, чтобы стать активным объектом, и с этого момента мы можем получить доступ к различным его свойствам.
По сути, переменный объект и активный объект — это одно, но в разных состояниях и стадиях.
цепочка прицелов (scope chain)
объемУказывает, как найти переменные, то есть определить права доступа выполняемого в данный момент кода к переменным. При поиске переменной сначала будет выполняться поиск в объекте-переменной текущего контекста, если не будет найдено, то будет поиск в объекте-переменной контекста исполнения родителя (родителя на лексическом уровне), и всегда найти переменный объект глобального контекста, то есть глобальный объект. Таким образом, связанный список, состоящий из переменных объектов нескольких контекстов выполнения, называетсяцепочка прицелов.
Вызывающий код текущего исполняемого блока кода (этот)
Если текущая функция вызывается как метод объекта или используетсяbind call applyЖдатьAPIВыполните вызов делегата, информация о вызывающем абоненте текущего блока кода (this value) сохраняется в текущем контексте выполнения, в противном случае по умолчанию используется глобальный вызов объекта.
оthisДетали создания немного раздражают.Если вам интересно, вы можете войти в эту главу, чтобы узнать.
Моделирование структуры данных контекста выполнения
Если приведенный выше полный контекст выполнения выражен в виде кода, он должен выглядеть следующим образом:
executionContext:{
[variable object | activation object]:{
arguments,
variables: [...],
funcions: [...]
},
scope chain: variable object + all parents scopes
thisValue: context object
}
Жизненный цикл контекста выполнения в ES3
Жизненный цикл контекста выполнения состоит из трех фаз, а именно:
- создать сцену
- этап выполнения
- фаза разрушения
создать сцену
Этап создания контекста выполнения функции происходит при вызове функции и до выполнения определенного кода в теле функции.Во время этапа создания JS-движок сделает следующее:
глобальный контекст выполнения
-
Перед выполнением глобального кода создайте глобальный контекст выполнения
-
Предварительная обработка глобальных данных
- Этот этап будетОбъявления инициализации для переменных и функций
- Глобальная переменная, определенная как var --> undefined, добавляется как свойство окна.
- Глобальная функция, объявленная функцией --> присваивание (забава), добавляется как атрибут окна.
- это --> задание(окно)
контекст выполнения функции
- При вызове функции перед подготовкой к выполнению тела функции создайте соответствующий объект контекста выполнения функции
- Предварительная обработка локальных данных
- Переменная формального параметра == "назначение (фактический параметр) --" добавлена как атрибут контекста выполнения
- arguments-->assignment-->(список аргументов), добавленный как свойство контекста выполнения
- Локальные переменные, определенные с помощью var --> undefined, добавляются как свойства контекста выполнения.
- функция Функция Бога --> назначение (забава) добавлена как атрибут контекста выполнения
- Создайте цепочку областей действия (детали построения были описаны ранее)
- this --> присваивание (вызов функционального объекта)
有没有发现这个创建执行上下文的阶段有变量和函数的初始化生命。这个操作就是 **变量声明提升**(变量和函数声明都会提升,但是函数提升更靠前)。
этап выполнения
На этапе выполнения JS-код начинает выполняться один за другим, на этом этапе JS-движок начинает присваивать значения определенным переменным, начинает обращаться к переменным по цепочке областей видимости, и если есть функция вызов внутри, он создает новый контекст выполнения и помещает его в стек выполнения.Передача управления...
фаза разрушения
Вообще говоря, когда выполнение функции завершено, текущий контекст выполнения (локальная среда) будет извлечен из стека контекста выполнения и уничтожен, а право управления будет передано контексту выполнения на один уровень выше стека выполнения.
Обратите внимание, что это только общий случай, случай замыканий отличается.
Определение закрытия:Функция, которая имеет доступ к переменной внутри другой функции. Проще говоря, если функция используется как возвращаемое значение другой функции и на нее ссылаются извне, то функция называется замыканием.
Сводка контекста выполнения ES3
дляES3Мы можем использовать следующий список, чтобы обобщить весь процесс выполнения программы:
- функция называется
- Перед выполнением кода конкретной функции создается контекст выполнения.
- Войдите в фазу создания контекста выполнения:
- Инициализировать цепочку областей видимости
- Создайте
arguments objectПроверяйте параметры в контексте, инициализируйте имена и значения и создавайте эталонные копии - Просканируйте контекст, чтобы найти все объявления функций:
- Для каждой найденной функции создайте свойство в объекте переменной с их собственным именем функции, которое содержит указатель на фактический адрес памяти.
- Если имя функции уже существует, указатель ссылки на свойство будет перезаписан.
- Просканируйте контекст, чтобы найти объявления переменных для всех переменных:
- Для каждого найденного объявления переменной создайте свойство в объекте переменной с собственным именем переменной и используйте
undefinedинициализировать - Если имя переменной уже существует как свойство в объекте переменной, ничего не делайте и сканируйте следующее
- Для каждого найденного объявления переменной создайте свойство в объекте переменной с собственным именем переменной и используйте
- Конечно
thisстоимость
- Войдите в фазу выполнения контекста выполнения:
- Запускайте/интерпретируйте код функции в контексте и присваивайте значения переменных по мере выполнения кода строка за строкой.
Контекст выполнения в ES5
ES5норма правоES3Часть концепции контекста выполнения была скорректирована.Самая важная корректировка заключается в удаленииES3средние переменные объекты и активные объекты дляКомпоненты лексического окружения ( Компонент LexicalEnvironment)а такжекомпонент переменной среды ( Компонент VariableEnvironment)альтернатива. такES5Контекст выполнения концептуально представлен следующим образом:
ExecutionContext = {
ThisBinding = <this value>,
LexicalEnvironment = { ... },
VariableEnvironment = { ... },
}
This Binding
-
ГлобальныйВ контексте исполнения
thisЗначение указывает на глобальный объект в браузереthisзначение указывает наwindowобъект, находясь вnodejsуказывая на этот файлmoduleобъект. -
функцияВ контексте исполнения
thisЗначение зависит от того, как была вызвана функция. В частности: привязка по умолчанию, неявная привязка, явная привязка (жесткая привязка),newПривязка, функция стрелки, конкретное содержание будет подробно объяснено в разделе [этот всесторонний анализ].
Лексическое окружение
Два лексических окружениякомпонент
- 1,Экологические записи: Фактическое место, где хранятся объявления переменных и функций.
- 2,Ссылка на внешнюю среду: имеет доступ к своему внешнему лексическому окружению
Два лексических окруженияТипы
- 1,глобальная среда: это лексическая среда без внешней среды, внешняя среда которой упоминается какnull. иметь глобальный объект (объект окна) и связанные с ним методы и свойства (например, методы массива) и любые определяемые пользователем глобальные переменные,
thisЗначение указывает на этот глобальный объект. - 2,функциональная среда: Пользовательские переменные в функции хранятся вЭкологические записи, включая
argumentsобъект. Ссылка на внешнюю среду может быть глобальной средой или внешней функциональной средой, содержащей внутреннюю функцию.
Может быть более интуитивно понятно смотреть непосредственно на псевдокод
GlobalExectionContext = { // 全局执行上下文
LexicalEnvironment: { // 词法环境
EnvironmentRecord: { // 环境记录
Type: "Object", // 全局环境
// 标识符绑定在这里
outer: <null> // 对外部环境的引用
}
}
FunctionExectionContext = { // 函数执行上下文
LexicalEnvironment: { // 词法环境
EnvironmentRecord: { // 环境记录
Type: "Declarative", // 函数环境
// 标识符绑定在这里 // 对外部环境的引用
outer: <Global or outer function environment reference>
}
}
переменная среда
Окружение переменных также является лексическим окружением, поэтому оно обладает всеми свойствами лексического окружения, определенными выше.
В ES6,Лексическийокружающая среда иПеременнаяСреда отличается тем, что первая используется для хранения объявлений функций и переменных (letа такжеconst)привязка, которая используется только для храненияПеременная(var)** обязательная.
Знакомство с примерами
let a = 20;
const b = 30;
var c;
function multiply(e, f) {
var g = 20;
return e * f * g;
}
c = multiply(20, 30);
Контекст выполнения выглядит так
GlobalExectionContext = {
ThisBinding: <Global Object>,
LexicalEnvironment: {
EnvironmentRecord: {
Type: "Object",
// 标识符绑定在这里
a: < uninitialized >,
b: < uninitialized >,
multiply: < func >
}
outer: <null>
},
VariableEnvironment: {
EnvironmentRecord: {
Type: "Object",
// 标识符绑定在这里
c: undefined,
}
outer: <null>
}
}
FunctionExectionContext = {
ThisBinding: <Global Object>,
LexicalEnvironment: {
EnvironmentRecord: {
Type: "Declarative",
// 标识符绑定在这里
Arguments: {0: 20, 1: 30, length: 2},
},
outer: <GlobalLexicalEnvironment>
},
VariableEnvironment: {
EnvironmentRecord: {
Type: "Declarative",
// 标识符绑定在这里
g: undefined
},
outer: <GlobalLexicalEnvironment>
}
}
переменное продвижениеПричина: на этапе создания объявление функции сохраняется в среде, а для переменной устанавливается значениеundefined(существуетvarслучае) или оставаться неинициализированным (вletа такжеconstна случай, если). Вот почему можно получить доступ до объявленияvarопределенная переменная (хотя онаundefined), но при доступе до объявленияletа такжеconstОпределенная переменная подскажет причину ошибки ссылки. Это называется переменным подъемом.
Сводка контекста выполнения ES5
дляES5Мы можем использовать следующий список, чтобы обобщить весь процесс выполнения программы:
- Программа запускается и создается глобальный контекст
- создать глобальный контекстЛексическое окружение
- СоздайтеРекордер объектной среды, который используется для определения вхождений вглобальный контекстСвязь между переменными и функциями в (отвечает за обработку
letа такжеconstопределенная переменная) - Создайтессылка на внешнюю среду, значениеnull
- СоздайтеРекордер объектной среды, который используется для определения вхождений вглобальный контекстСвязь между переменными и функциями в (отвечает за обработку
- создать глобальный контекстпеременная среда
- СоздайтеРекордер объектной среды, который держитоператор объявления переменнойПривязки, созданные в контексте выполнения (отвечают за обработку
varПеременная определена, начальное значение равноundefinedпривести к снятию декларации) - Создайтессылка на внешнюю среду, значениеnull
- СоздайтеРекордер объектной среды, который держитоператор объявления переменнойПривязки, созданные в контексте выполнения (отвечают за обработку
- Конечно
thisЗначение является глобальным объектом (в качестве примера возьмем браузер, этоwindow)
- создать глобальный контекстЛексическое окружение
- Вызывается функция, создается контекст функции
- создать контекст функцииЛексическое окружение
- СоздайтеДекларативный регистратор среды, в котором хранятся переменные, функции и параметры, он содержитargumentsобъект (в этом объекте хранится карта индексов и параметров) и параметры, переданные в функциюlength. (отвечает за обработку
letа такжеconstопределенная переменная) - Создайтессылка на внешнюю среду, значением является глобальный объект или родительская лексическая среда (область)
- СоздайтеДекларативный регистратор среды, в котором хранятся переменные, функции и параметры, он содержитargumentsобъект (в этом объекте хранится карта индексов и параметров) и параметры, переданные в функциюlength. (отвечает за обработку
- создать контекст функциипеременная среда
- СоздайтеДекларативный регистратор среды, в котором хранятся переменные, функции и параметры, он содержитargumentsобъект (в этом объекте хранится карта индексов и параметров) и параметры, переданные в функциюlength. (отвечает за обработку
varПеременная определена, начальное значение равноundefinedпривести к снятию декларации) - Создайтессылка на внешнюю среду, значением является глобальный объект или родительская лексическая среда (область)
- СоздайтеДекларативный регистратор среды, в котором хранятся переменные, функции и параметры, он содержитargumentsобъект (в этом объекте хранится карта индексов и параметров) и параметры, переданные в функциюlength. (отвечает за обработку
- Конечно
thisстоимость
- создать контекст функцииЛексическое окружение
- Войдите в фазу выполнения контекста выполнения функции:
- Запускайте/интерпретируйте код функции в контексте и присваивайте значения переменных по мере выполнения кода строка за строкой.
стек выполнения
Стек выполнения, также известный как «стек вызовов» в других языках программирования, представляет собой стек со структурой данных LIFO (последним вошел, первым обслужен), которая используется для хранения всех контекстов выполнения, созданных при выполнении кода.
Когда движок JavaScript впервые встречает ваш сценарий, он создает глобальный контекст выполнения и помещает его в текущий стек выполнения. Всякий раз, когда механизм встречает вызов функции, он создает новый контекст выполнения для этой функции и помещает его на вершину стека.
Механизм выполняет функции, контекст выполнения которых находится на вершине стека. Когда выполнение функции завершается, контекст выполнения извлекается из стека, и поток управления переходит к следующему контексту в текущем стеке.
Давайте разберем следующий пример кода:
let a = 'Hello World!';
function first() {
console.log('Inside first function');
second();
console.log('Again inside first function');
}
function second() {
console.log('Inside second function');
}
first();
console.log('Inside Global Execution Context');
Стек контекста выполнения приведенного выше кода.
Когда приведенный выше код загружается в браузер, механизм JavaScript создает глобальный контекст выполнения и помещает его в текущий стек выполнения. при встречеfirst()Когда вызывается функция, механизм JavaScript создает новый контекст выполнения для функции и помещает его поверх текущего стека выполнения.
когда изfirst()вызов внутри функцииsecond()функция, движок JavaScriptsecond()Функция создает новый контекст выполнения и помещает его поверх текущего стека выполнения. когдаsecond()После выполнения функции ее контекст выполнения извлекается из текущего стека, и поток управления достигает следующего контекста выполнения, а именноfirst()Контекст выполнения функции.
когдаfirst()После выполнения его контекст выполнения извлекается из стека, и поток управления достигает глобального контекста выполнения. Как только весь код выполнен, механизм JavaScript удаляет глобальный контекст выполнения из текущего стека.
В заключение
- Этап создания контекста выполнения делится на три шага: связывание this, создание лексического окружения и переменное окружение.Разница между ними заключается в том, что в лексическом окружении хранятся переменные, объявленные объявлениями функций и const let, а в переменном окружении хранятся только переменные, объявленные var.
- Лексическая среда в основном состоит из двух частей: записи среды и записи импорта внешней среды.Глобальный контекст отличается от записи импорта внешней среды контекста функции.Глобальный контекст равен нулю, а функция является глобальной средой или другие функциональные контексты. Запись среды также отличается, глобальная запись называется записью среды объекта, а функция называется декларативной записью среды.
- Вы должны понимать, почему есть подъем переменных, подъем функций, а не const.
- Понятия переменных объектов и активных объектов до ES3 объясняются лексическим окружением и переменным окружением после ES5.Эти два понятия не противоречат друг другу, и последнее легче понять. Я должен сказать, что я устал читать статьи по теме, и я надеюсь, что это поможет тем из вас, кому суждено Так вот, эта статья заканчивается.