Основное руководство 11-го Frontend Sprint — Контекст выполнения / Цепочка задач / Замыкания / Граждане первого класса

JavaScript
Основное руководство 11-го Frontend Sprint — Контекст выполнения / Цепочка задач / Замыкания / Граждане первого класса

предисловие

Привет всем, мне неловко, я много работаю каждый день, вы можете обновить повышение заработной платы, генеральный директор, генеральный директор, генеральный директор, Ин Бай Фумэй, пик, думая об этом, я думаю, что есть небольшое волнение.

Это содержание моей 11-й статьи✍, я не хочу воспринимать 👉 эту статью как заметку для заучивания, или подытожить какие-то ключевые моменты. Вместо этого я надеюсь по-настоящему понять, освоить, проанализировать суть ее содержания построчно через эту статью и обдумать содержание каждой строки и абзаца.

Я надеюсь, что смогу объяснить каждый пункт знаний (конечно, если вы не понимаете какой-либо пункт, вы можете обсудить его в области комментариев!) ⏰, время начинается!

Если вы нашли эту статью полезной, пожалуйста,Нравится, Избранное, Комментарий, оставьте следы своего обучения 👣, я бы хотел поговорить об этом 😃

1. Контекст выполнения/цепочка областей/замыкание

Что, черт возьми, что это за чертовщина? 😑, некоторые разработчики должны это понимать, но для новичков или (для новичков) контекст выполнения и стек выполнения должны быть пустыми в их сознании? 📖, скажешь да?

1.1 Так что же такое контекст выполнения?

Контекст выполнения, который является относительно абстрактным понятием, то есть текущий код JavaScriptПри разборе и выполненииСреда, поэтому запуск любого кода в JavaScript выполняется в контексте выполнения.

Существует три типа контекстов выполнения:

🔷Первый тип: глобальный контекст выполнения

Помните, что есть только один глобальный контекст выполнения, то есть в программе может быть только один глобальный контекст выполнения, если он в браузере, то глобальный объект — это объект окна, и this указывает на этот глобальный объект.

🔷Второй тип: контекст выполнения функции

Контекстов выполнения функции может быть несколько или даже бесконечное количество; они создаются только при вызове функции (контекст выполнения функции), а новый контекст выполнения создается каждый раз при вызове функции.

🔷Третий тип: контекст выполнения функции Eval

Контекст выполнения функции Eval, какого черта! Что это? Предположительно, некоторые программисты редко используют это, поэтому не нужно объяснять, но помните, что это код, работающий в функции eval, только код в функции eval имеет контекст выполнения функции eval.

После понимания контекста выполнения (т. е. среды) вам необходимо понять поток выполнения в программе JavaScript, а также поток механизма управления (стек выполнения).

1.2 Стек выполнения

На самом деле стек выполнения (стек вызовов) — это стек со структурой LIFO, который используется для хранения всех контекстов выполнения, созданных во время выполнения выполнения кода.

Процесс добавления и извлечения стека — стек контекста выполнения

Когда механизм JavaScript запускает код JavaScript, он создает глобальный контекст выполнения и помещает его в текущий стек выполнения. (Функция не была разрешена, выполнена или вызвана) Существует только глобальный контекст выполнения. Всякий раз, когда движок находит вызов функции, движок создает новый контекст выполнения функции для функции и помещает его на вершину стека ( текущий контекст выполнения). вершина стека)

После того, как движок выполняет функцию, контекст выполнения которой находится на вершине стека, соответствующий контекст выполнения функции извлекается из стека, и управление достигает контекста под ним в текущем стеке (если есть следующая функция).

Жизненный цикл контекста выполнения:

Процесс создания: 1. Создать переменный объект, 2. Установить цепочку областей действия, 3. Определить точку этого.

Процесс выполнения: 1. Назначение переменной, 2. Ссылка на функцию, 3. Выполнение другого кода.

Фаза уничтожения: всплывает из стека после выполнения, ожидая повторного использования.

Теперь, когда мы понимаем, как движки JavaScript управляют контекстами выполнения, как нам их создать? 😲

1.3 Создание контекста выполнения

Узнайте, как создать контекст выполнения, который создается в два этапа:

  • Первый: этап создания — контекст выполнения

  • Второй тип: фаза выполнения - контекст выполнения

Контекст выполнения создается на этапе создания, что происходит на этапе создания:

Фаза создания — контекст выполнения

Определите точку этого, значение, определенное или установленное этим

В глобальном контексте выполнения значение this указывает на глобальный объект, в браузере значение this ➡объект окна, в nodejs оно указывает на ➡объект модуля

В контексте выполнения функции значение this зависит от того, как была вызвана функция (т. е. как она была вызвана). Когда он вызывается для ссылочного объекта, устанавливает значение this для этого объекта, в противном случае значение this устанавливает значение this для глобального объекта или неопределенного (в строгом режиме)

Давайте посмотрим на этот пример кода:

const dadaqianduan = {
    name: 'dadaqiandaun',
    love: '魔王哪吒',
    foo: function(){
        console.log('dadaqianduan');
    }
}

dadaqianduan.foo();
// this的指向dadaqianduan,因为foo是通过dadaqianduan对象引用调用的

const Jeskson = dadaqianduan.foo;
Jeskson();
// this指向全局窗口对象,因为没有给出对象引用

Абстрактно лексическое окружение выглядит в псевдокоде следующим образом:

GlobalExectionContext = {  
// 全局执行上下文
  LexicalEnvironment: {    	  
  // 词法环境
    EnvironmentRecord: {   		
    // 环境记录
      Type: "Object",      		   
      // 全局环境
      // 标识符绑定在这里 
      outer: <null>  	   		   
      // 对外部环境的引用
  }  
}

FunctionExectionContext = { 
// 函数执行上下文
  LexicalEnvironment: {  	  
  // 词法环境
    EnvironmentRecord: {  		
    // 环境记录
      Type: "Declarative",  	   
      // 函数环境
      // 标识符绑定在这里 			  
      // 对外部环境的引用
      outer: <Global or outer function environment reference>  
  }  
}

Компонент LexicalEnvironment создан

Сначала увидеть лексическое окружение? Что такое лексическое окружение? Как понять это понятие существительного? 😮

Итак, прежде всего, определение лексического окружения:

Описание лексической среды в официальной спецификации, тип спецификации, используемый для определения ассоциации идентификаторов с конкретными переменными и функциями с точки зрения структуры лексического вложения кода ECMAScript.

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

Лексическое окружение состоит из записи окружения и возможной нулевой ссылки (Null) внешнего лексического окружения. Обычно лексическое окружение связано с определенной синтаксической структурой кода ECMAScript.

Записи окружения — это место, где объявления переменных и функций хранятся в лексическом окружении.

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

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

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

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

Следующий код:

function foo(a,b){
    var c = a+b;
}
foo(1,2);
// 参数对象
参数: {0:1,1:2,长度:2}

Ссылка на внешнее окружение, означающая, что он имеет доступ к своему внешнему лексическому окружению, и если переменная не найдена в текущем лексическом окружении, механизм JavaScript может искать переменную во внешнем окружении.

Вот этого я не понимаю.Лексическое окружение состоит из двух компонентов:

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

В псевдокоде:

function LexicalEnvironment() {
    this.EnvironmentRecord = undefined;
    this.outer = undefined; 
    //outer Environment Reference
}

Записи среды записывают привязки идентификаторов, созданные в рамках связанной с ними лексической среды. 👇

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

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

Теперь представьте лексическое окружение в коде:

var a = 1;
var b = 2;

function foo(){
    console.log('达达前端');
}

Лексическое окружение для этого кода представляет собой:

lexicalEnvironment = {
    a: 1,
    b: 2,
    foo: <ref. to foo function> 
}
Фаза выполнения — контекст выполнения

На этом этапе выполняется присвоение всех этих переменных, и, наконец, выполняется код.

Создан компонент VariableEnvironment

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

Говоря о причине подъема переменных, на этапе создания объявления функций хранятся в среде, а переменные либо устанавливаются в значение undefined, либо остаются неинициализированными.

Итак, вот почему переменные, определенные как var, могут быть доступны до объявления, но переменные, определенные как let и const, получают ошибку ссылки hoist, если к ним обращаются до объявления.

Теперь для примера:
var da1, da2 = 1;
function foo() {
    var da3, da4;
};
foo();

Когда js выполняет этот код, он создает лексическое окружение (глобальное окружение-ge), определяет запись окружения (ge), которая содержит записи идентификаторов da1, da2, foo, и устанавливает ссылку на внешнее лексическое окружение, потому что ( ge ) уже находится в самой внешней точке, поэтому ссылка на внешнее лексическое окружение равна Null, и в этой точке устанавливается (ge).

Затем выполните код, когда выполнение достигает foo(), js вызывает функцию foo, функция foo представляет собой (FunctionDeclaration), js начинает выполнение функции и создает новое лексическое окружение, представленное как (ge2), и устанавливает внешнее лексическое окружение (ge2) Референтом, очевидно, является запись окружения (da3, da4) of (ge), (ge2).

Все создание лексического окружения и записей окружения невидимо и выполняется внутри компилятора.

Пример лексического окружения:

全局的词法环境,源文件代码,就是一个词法环境
函数代码,eval词法环境,with结构,catch结构

// 全局的词法环境
var a = 1;
function da1() {
    // 函数da1的词法环境
    var b = 2;
    function da2() {
    // 函数da2的词法环境
        return a*b;
    }
    return da2();
}

with({c:3, d:5}){
    // with声明的词法环境
    console.log(this.c)
}

try {
    var e = da1()
} catch(e){
    // catch块声明的词法环境
    console.log('达达前端,魔王哪吒')
}

1.4 Процесс стека контекста выполнения JavaScript

Думая, движок JavaScript не анализирует и не выполняет программу построчно, а анализирует и выполняет ее по частям. Как управлять таким количеством созданных контекстов выполнения?

Таким образом, движок JavaScript создает стек контекста выполнения для управления.

1.5 Вопросы для интервью

比较下面两段代码,试述两段代码的不同之处
// A--------------------------
var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f();
}
checkscope();

// B---------------------------
var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f;
}
checkscope()();

Объяснение следующее:

Поскольку в JavaScript используется лексическая область видимости, область действия функции зависит от того, где она была создана.

  • Когда первая внутренняя функция f будет инициализирована, она создаст активный объект, добавит свойство с именем scope и создаст скрытое свойство [[scope]], которое используется для указания на родительский активный объект. Когда эта функция выполняется, области будет присвоено значение, после ее [[scope]], вы можете найти значение родителя, вернуть ссылочную переменную и продолжить возвращаться за пределы функции. выходная локальная область
  • Вторая внутренняя функция f также создает активный объект при его инициализации, и к активному объекту добавляется атрибут с именем scope attribute. Также создает скрытое свойство [[scope]], указывающее на родительский активный объект. Когда checkscope выполняется в первый раз и входит в тело функции checkscope, возвращается значение указателя f (ссылка на внутреннюю функцию), а не переменная исходного значения, которая возвращается напрямую. Второе выполнение не входит в тело функции f.Установлен внутренний активный объект и приватное свойство [[scope]], ищет значение переменной области видимости по этой цепочке и возвращается для формирования замыкания.

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

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

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

К объекту переменных добавляются только объявления функций, а не выражения функций.

// 函数声明
function da(){}
console.log(typeof da); // "function"

// 函数表达式
var da2 = function da1(){};
console.log(typeof da2); // "function"
console.log(typeof da1); // "undefined"

Когда редактор Js начинает выполняться, глобальный объект инициализируется, чтобы связать глобальную область видимости.Для глобальной среды глобальный объект является объектом переменной.

Ранее упоминалось, что объект переменной не читается программой, доступ к объекту переменной имеет только компилятор. На стороне браузера глобальный объект представлен как объект окна, то есть глобальный объект ===window====объект переменной глобальной среды.

При вызове функции создается активный объект, который назначается контексту выполнения. Затем возьмите его активный объект как переменный объект, и активный объект инициализируется специальными аргументами объекта.

объект arguments, этот объект не существует в глобальной среде

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

function dada(name, love){
    var job = 'it',
    function dada1(){}
}
dada('Jeskson',girl);

При вызове дада активный объект AO будет создан в контексте выполнения дада, и он будет инициализирован как AO=[аргументы], затем AO будет использоваться как переменный объект переменный объект, vo будет инициализирован как переменная, в это время VO=[аргументы].concat ([имя,любовь,пробежка]).

Лексическая область видимости, слово, слово, метод, грамматика — это слова (идентификаторы, примитивные значения, операторы и т. д.), грамматика — это различные грамматические правила в JavaScript, поэтому лексическая область видимости — это глобальная функция js.

Область действия управляет видимостью и жизненным циклом переменных и параметров. Все переменные, определенные в блоке кода, не видны за пределами блока кода. Переменные, определенные в блоке кода, будут освобождены после выполнения блока кода. Параметры и переменные в функции невидимы вне функции, и любая переменная, определенная внутри функции, видна внутри функции.

В JavaScript используется лексическая область видимости, которая является статической областью видимости, а область действия функции определяется при ее определении.

1.6 Динамическая область

При динамической области видимости область действия функции определяется при ее вызове.

В целом, преимущество области действия заключается в том, что внутренние функции могут обращаться к аргументам и переменным внешней функции, которая их определяет, за исключением this и arguments.

Подводя итог, каждый контекст выполнения имеет переменный объект, цепочку областей видимости и this.

1.7 Цепочка областей применения

Эта статья иллюстрирует точки знаний цепочки областей:JavaScript от прототипа к цепочке прототипов

Цепочка областей действия: при поиске переменной она сначала будет искать объект переменной текущего контекста.Если она не будет найдена, она будет искать объект переменной родительского контекста выполнения и всегда найдет объект переменной контекста. глобальный контекст, то есть глобальный объект. (то есть состоит из переменных нескольких контекстов выполнения)

Внутри функции есть внутреннее свойство [[scope]]. При создании функции все родительские переменные будут сохранены в этом свойстве. [[scope]] — это иерархическая цепочка всех объектов родительских переменных, которая не представляет собой полная цепочка объемов.

1.8 Закрытие

Первое: как использовать замыкания; второе: что такое замыкания; третье: когда создаются замыкания; четвертое: когда они уничтожаются.

вопросы интервью
for(var i=0; i<5; i++) {// 从0-4
    setTimeout(function(){
        console.log(new Date, i);
    },1000);
}
console.log(new Date, i);

Используйте замыкание, чтобы сделать вывод5 -> 0,1,2,3,4

for (var i = 0; i < 5; i++) {
    (function(j) {  // j = i
        setTimeout(function() {
            console.log(new Date, j);
        }, 1000);
    })(i);
}

console.log(new Date, i);

оптимизация:

var output = function(i) {
    setTimeout(function(){
        console.log(new Date, i);
    },1000);
};
// 变量赋值匿名函数
for(var i=0; i<5; i++){
    output(i); // 传递i值
}
console.log(new Date, i);
// 这段代码最后的i在运行时会报错
for(let i=0; i<5; i++) {
    setTimeout(function(){
        console.log(new Date, i);
    },1000);
}
console.log(new Date, i);
for(var i = 0; i<5; i++){
    function(j){
        setTimeout(function(){
            console.log(new Date, j);
        }, 1000 * j);
    })(i);
}

setTimeout(function(){
    console.log(new Date, i);
},1000 * i);

Написано с использованием es6:

const tasks = []; // 存放异步操作promise
const output = (i) => new Promise((resolve) => {
    setTimeout(()=>{
        console.log(new Date, i);
        resolve();
    }, 1000 * i);
});
for(var i=0; i<5; i++){
    tasks.push(output(i));
}

Promise.all(tasks).then(()=>{
    setTimeout(()=>{
        console.log(new Data, i);
    },1000);
});
// async/await
const sleep = (timeountMS) => new Promise((resolve) => {
    setTimeout(resolve, timeountMS);
});

(async () => {  
    for (var i = 0; i < 5; i++) {
        if (i > 0) {
            await sleep(1000);
        }
        console.log(new Date, i);
    }

    await sleep(1000);
    console.log(new Date, i);
})();
window.setTimeout

setTimeout()Метод устанавливает таймер, который выполняет функцию или указанный фрагмент кода по истечении времени таймера.

var id = setTimeout(fn, delay)Запускает один таймер, который вызовет указанную функцию после задержки, возвращая уникальный идентификатор, который можно использовать для отмены таймера позже.

а такжеvar id = setInterval(fn, delay)похожий наsetTimeoutНо функция вызывается непрерывно, пока не будет отменена.clearInterval(id),clearTimeout(id), получает идентификатор калькулятора и останавливает обратный вызов калькулятора.

Задержка калькулятора не гарантируется, так как весь JavaScript в браузере выполняется в одном потоке, поэтому асинхронные события запускаются только при наличии пробела в выполнении.

Поскольку JavaScript может выполнять только один фрагмент кода за раз, каждый из этих блоков кода «блокирует» процесс других асинхронных событий, которые ставятся в очередь для последующего выполнения при возникновении асинхронного события.

setTimeoutа такжеsetInterval:

setTimeout(function(){
    setTimeout(arguments.callee, 10);
},10);
setInterval(function(){
    
},10);
// setTimeout代码在上一次执行回调之后将始终至少有10ms的延迟,最终可能会更多,但是不会少,而setInterval无论最后一次执行回调的时间如何,都会尝试每10ms执行

Promise

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

Пример:

const promise1 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve('foo');
    },200);
});

promise1.then((value)=>{
    console.log(value);
});
console.log(promise1);

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

ОдинPromiseЕсть несколько состояний 😬:

  1. pendingНачальное состояние, которое не является ни состоянием успеха, ни состоянием отказа;
  2. fulfilledУказывает, что операция завершена успешно;
  3. rejectedУказывает, что операция не удалась.

Методы Promise.prototype.then и Promise.prototype.catch возвращают объекты обещаний, поэтому их можно объединить в цепочку.

метод:

Promise.prototype.catch(onRejected)Добавляет обратный вызов отклонения к текущему промису, возвращая новый промис.

Promise.prototype.then(onFulfilled, onRejected)Добавьте обратные вызовы разрешения и отклонения к текущему обещанию и верните новое обещание, которое будет разрешено с возвращаемым значением обратного вызова.

Promise.prototype.finally(onFinally)Добавьте обратный вызов обработчика событий к текущему объекту обещания и верните новый объект обещания после разрешения исходного объекта обещания.

Пример:

function myAsyncFunction(url) {
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open('GET',url);
        xhr.onload = () => resolve(xhr.responseText);
        xhr.onerror = () => reject(xhr.statusText);
        xhr.send();
    }
}

async function

async functionиспользуется для определения возвратаAsyncFunctionАсинхронный хэш объекта.

Пример:

function resolveAfter2Seconds() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('resolved');
    }, 2000);
  });
}

async function asyncCall() {
  console.log('calling');
  const result = await resolveAfter2Seconds();
  console.log(result);
  // expected output: 'resolved'
}

asyncCall();

结果:

> "calling"
> "resolved"

Асинхронная асинхронная функция может содержать инструкцию await, которая приостанавливает выполнение асинхронной функции, ожидает выполнения промиса, затем возобновляет асинхронную функцию и возвращает результат.

Ключевое слово await допустимо только внутри асинхронных функций. Если вы используете его вне асинхронной функции, будет выдана синтаксическая ошибка.

1.9 Мощные замыкания

Пример: 😦

"use strict";
var dada = (function outerFunction(){
    var da = 1;
    return {
        inc: function innerFunction(){
            return da++;
        }
    };
}());
dada.inc(); // 1
dada.inc(); // 2
dada.inc(); // 3

Код, работающий в глобальной среде: 😫

// my_script.js
"use strict";

var foo = 1;
var bar = 2;

Никаких вложенных функций 😊

"use strict";
var foo = 1;
var bar = 2;

function myFunc() {
  var a = 1;
  var b = 2;
  var foo = 3;
  console.log("inside myFunc");
}

console.log("outside");

myFunc();

Когда выполняется myFunc, отношения между объектами показаны на следующем рисунке.

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

Замыкание — это внутренняя функция, которая имеет доступ к внешней области видимости. Переменные, созданные с помощью var, имеют только область действия функции, переменные, созданные с помощью let и const, имеют область действия как функции, так и области действия блока.

Вложенные области:

(function dada(){
    let a = 1;
    function dada1() {
        console.log(a);
    }
    dada1();
})();
// dada1函数就是一个闭包
// 可以通过在一个函数内部或者{}块里面定义一个函数来创建闭包

Внутренние функции могут обращаться к внешним функциям:

(function autorun(da){
    let da1 = 1;
    setTimeout(function log(){
      console.log(da1);//1
      console.log(da);//6
    }, 10000);
})(6);

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

Пример:

(function dada(){
    let a = 1;
    function da(){
      console.log(a);
    };
    
    function run(fn){
      let a = 100;
      fn();
    }
    
    run(da);//1
})();

Область видимости функции dada() — это лексическая область действия функции da().

После того, как внешняя область действия завершила выполнение, а внутренняя функция по-прежнему (упомянутая в другом месте), закрытие действительно работает. 😏

(function dadaqianduan(){
    let a = 1;
    setTimeout(function log(){
      console.log(a);
    }, 1000);
})();
(function dada(){
    let a = 1;
    $("#btn").on("click", function log(){
      console.log(a);
    });
})();
(function dada(){
    let ax = 1;
    fetch("http://").then(function log(){
      console.log(a);
    });
})();

Замыкания только хранят ссылки на внешние переменные, но не копируют значения этих внешних переменных.Учтите, будет плохо, если эта штука будет использовать слишком много памяти 😂😂

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

При сборке мусора 😱 локальные переменные уничтожаются по завершении выполнения функции 😱, если на них еще нет ссылок. Когда само замыкание подвергается сборке мусора, приватное состояние в замыкании впоследствии также подвергается сборке мусора.

Функции являются гражданами первого класса

Вы часто слышите - «Функции - это первые гражданины», в программировании граждане первоклассных классов могут использоваться в качестве параметров функций, как функциональные значения возврата, а также могут быть назначены переменные. 😘

Например, строки являются объектами первого класса почти во всех языках программирования.Строки могут использоваться как параметры функции, как возвращаемые значения функции и могут быть присвоены переменным.

Таким образом, функции являются гражданами первого класса в JavaScript. Граждане первого класса имеют наивысший приоритет, и когда функция считается «гражданином первого класса», именно эта функция имеет приоритет.

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

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

How do JavaScript closures work under the hood

Understanding Execution Context and Execution Stack in Javascript

How JavaScript Timers Work

** Предварительное собеседование (80% соискателей терпят неудачу в серии): начиная с закрытия

Расширенное программирование с помощью JavaScript (3-е издание)

Полное руководство по JavaScript