Код Javascript запускается с «Контекстом выполнения». Поскольку само имя включает в себя «контекст», оно представляет собой среду/обстоятельства выполнения кода. Контекст выполнения имеет все, что нужно для запуска текущего кода.
Всякий раз, когда вы запускаете код JS, должен быть контекст выполнения. Сначала JS Engine запускает JS-код, создается «Глобальный контекст выполнения», который также помещается в «Стек выполнения». и Затем всякий раз, когда вызываются какие-либо функции, создается «Контекст выполнения функции», который помещается в «Контекст выполнения».
Если вы думаете, что весь код JS представляет собой функцию, контекст выполнения этой функции — «глобальный контекст выполнения».
Компонент и состав контекста выполнения немного отличаются в разных версиях ES. Но есть общие 4 компонента.
- Переменная среда
- Лексическое окружение
- Справочник по внешней среде
- Эта привязка
Ниже в этой статье будет использоваться объект ExecutionContext. Я еще раз повторяю, что форма/состав компонента EC отличается в разных версиях es, но это не так важно для понимания контекста выполнения.
ExecutionContext = { VariableEnvironment = {}, LexicalEnvironment = {} OuterEnvrionmentReference = null or other EC, thisBinding = anyother object }
1. Переменная среда
Вы можете знать подъем, а также то, что поднимается. Это var
переменная и function declaration.
Как и подъемные устройства, переменная среда хранит var
переменных и function declaration
.
var name = "heal"; var sex = "male"; function sayHi() { var a = 1; console.log("hi") } sayHi();
VariableEnvironment вышеприведенного кода выглядит так, как показано ниже.
// Execution Stack -------------------------------------------------------------------- | | sayHi FunctionExecutionContext: { | VariableEnvironment: { | a: 1; | } |} | --------------------------------------------------------------------| |GlobalExecutionContext: { | VariableEnvironment: { | name: "heal"; | sex: "male"; | sayHi: <ref. <sayHi func> | }, |} | --------------------------------------------------------------------
Если вам интересно, почему значение функции sayHi является эталонным, посмотрите эту ссылку (управление памятью JS)
2. Лексическое окружение
Лексическая среда хранит let
, const
переменных.
let name = "kim"; const name2 = "Lee"
LexicalEnvironment будет выглядеть следующим образом:
ExecutionContext: { LexicalEnvironment: { name: "kim"; name2:"Lee"; } }
3. Справочник по внешней среде
Другое название — Scope. Вы слышали много размаха. Вот и все.
Внешняя ссылка (внутренней) лексической среды — это ссылка на лексическую среду, которая логически окружает внутреннюю лексическую среду. (из https://262.ecma-international.org/6.0/)
Что вы должны иметь в виду, так это то, что «Думайте, что это просто место, где эта функция объявлена». Не думайте, где он вызывается. давайте посмотрим ниже коды
Внешний пример 1.
function outFn() { var a = 1; function inFn() { return a; } } outFn(); // return 1
Контекст выполнения вышеприведенного кода помещается в стек, как показано ниже.
// Execution Stack -------------------------------------------------------------------- | |inFn FunctionExecutionContext: { | variavleEnvironment: {}, | outerEnv: outFn execution context |} | -------------------------------------------------------------------- | |outFn FunctionExecutionContext: { | variavleEnvironment: { | a: 1 | isFn: <ref. isFn func> | }, | outerEnv: global execution context |} | --------------------------------------------------------------------| |GlobalExecutionContext: { | VariableEnvironment: { | outFn: <ref, outFn func> | }, | outerEnv: null, // global execution context's outerEnv is "null" |} | --------------------------------------------------------------------
Функция isFn
не имеет a
переменной. поэтому проверьте externalEnvironment (функция outFn
). и может вернуть значение a
.
Внешний пример 2.
Угадайте, что вернет функцияf2
.
var a = 1; function f1() { return a; } function f2() { var a = 2; f1(); } f2(); // ???
Функция f2
возвращает 1
. Как вы догадались, он вернет 2
?
В начале outerEnv
я напомнил, что "представьте, что это просто место, где объявлена эта функция".
Стек контекста выполнения примера 2 выглядит следующим образом:
// Execution Stack -------------------------------------------------------------------- | | f1 FunctionExecutionContext: { | variavleEnvironment: {}, | outerEnv: global execution context // !! CHECK THIS OUT. !! |} | -------------------------------------------------------------------- | | f2 FunctionExecutionContext: { | variavleEnvironment: { | a: 2 | }, | outerEnv: global execution context |} | --------------------------------------------------------------------| |GlobalExecutionContext: { | VariableEnvironment: { | a: 1, | f1: <ref, f1 func>, | f2: <ref, f2 func> | }, | outerEnv: null, // global execution context's outerEnv is "null" |} | --------------------------------------------------------------------
Внешняя среда f1 – это GlobalExecutionContext. Потому что externalEnv определяется там, где объявлена эта функция.
4. эта привязка
Вы думаете, что ключевое слово this
означает «кто вызывает эту функцию».
const functions = { sayHi: function() { console.log('Hi'); };, ~~ } functions.sayHi(); const sayHiGlobal = functions.sayHi; sayHiGlobal();
Стек ExecutionContext выглядит следующим образом:
// Execution Stack -------------------------------------------------------------------- | | functions.sayHi ExecutionContext: { | thisBinding: functions object |} | --------------------------------------------------------------------| |GlobalExecutionContext: { | LexicalEnvironment: { | functions: <ref. functions.object>, | sayHi: <ref. functions.sayHi> | }, |} | --------------------------------------------------------------------
После возврата из functions.sayHi() контекст functions.sayHi
извлекается, а контекст sayHiGlobal помещается в стек.
// Execution Stack -------------------------------------------------------------------- | | sayHiGlobal ExecutionContext: { | outerEnv: GlobalExecutionContext, | thisBinding: global object // |} | --------------------------------------------------------------------| |GlobalExecutionContext: { | LexicalEnvironment: { | functions: <ref. functions.object>, | sayHi: <ref. functions.sayHi> | }, |} | --------------------------------------------------------------------
Напомните еще раз, что this
– это "кто вызывает эту функцию".
Закрытие с контекстом выполнения
Вы можете немного больше понять, как Closure работает в контексте выполнения.
Вы уже слышали closure
объяснение, похожее на приведенное ниже.
Замыкание — это комбинация объединенной (вложенной) функции со ссылками на ее окружающее состояние (лексическое окружение). Другими словами, замыкание дает вам доступ к области действия внешней функции из внутренней функции. В JavaScript замыкания создаются каждый раз, когда создается функция, во время создания функции. — закрытие МДН
Но этого недостаточно для понимания. Давайте углубимся в контекст выполнения.
function createClosure() { var a = 1; function inner() { return a; } return inner; } var f1 = createClosure(); // !! POINT_1 !! f1(); // return 1;
f1
закрывается. Потому что может получить доступ к var a
. Давайте посмотрим, как функция f1() может получить доступ к переменной a
.
В POINT_1 стек выполнения выглядит ниже.
// Execution Stack -------------------------------------------------------------------- | | createClosure FunctionExecutionContext: { | variableEnvironment: { | a:1, | inner: <ref. inner func> | }, | outerEnv: global execution context |} | --------------------------------------------------------------------| |GlobalExecutionContext: { | VariableEnvironment: { | f1: <ref. fn func>, | createClosure: <ref, createClosure func> | }, | outerEnv: null, |} | --------------------------------------------------------------------
После POINT_1 createClosure
извлекается из стека, а замыкание создается в верхней части стека выполнения. поэтому функцияfn
по-прежнему имеет доступ к переменной a
.
// Execution Stack -------------------------------------------------------------------- | | CLOSURE: { | variableEnvironment: { | a:1, | }, |} | --------------------------------------------------------------------| |GlobalExecutionContext: { | VariableEnvironment: { | f1: <ref. fn func>, | createClosure: <ref, createClosure func> | }, | outerEnv: null, |} | --------------------------------------------------------------------
С этим изображением: закрытие создается и помещается в стек. Лучше понять closure
.
далее…
Есть еще одна важная концепция: как создается контекст выполнения.
Следующая статья будет «Контекст выполнения, созданный в два этапа: фаг создания, фаг выполнения».