Примечание. Я импортировал его из своего блога. Так что это может быть не похоже на исходный пост. Если вы хотите прочитать оригинальный блог. Посетите здесь.

Является ли JavaScript синхронным? Да.

Является ли JavaScript однопоточным-многопоточным? Да.

Хватит таких жаргонизмов, как threadи синхронный. Давайте сначала разберемся с этими терминами.

Синхронно = Последовательность = один за другим.

var a = 10; //first line 
var b = 'Javascript'; //second line 
 
Here synchronous means: 
The first variable 'a' is assigned to 10, 
and then variable 'b' is assigned to 'Javascript.'  
The first line is executed, and then the second line is executed.

Однопоточный = обработка одной строки за раз.

var a = 10 ; //first line
var b = 'Javascript'; //second line
 
Here single threaded means:
When the process of assigning 10 to variable 'a' - no other process happens at that time. 
Only when the first line finishes the second line starts.
If the first line or process fails, the whole code fails.

Копать глубже!

Где происходит описанный выше процесс? Эта простая операция с двумя присваиваниями имеет общие этапы.

  • Есть две переменные: a и b. Для их хранения должна быть выделена память.
  • Код выполняется. т. е. операция присваивания переменной «a» и «b».

Эти шаги происходят в 'контексте выполнения'.Новый термин? Верно!

Контекст выполнения = место или среда, в которойсоздается памятьивыполняется кодn.

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

Второй этап — выполнение кода:

Контекст выполнения =создание памяти+выполнение кодаn.

Обратите внимание, что переменные a и b инициализированыв значение undefinedвфазе памяти. Здесь переменные инициализируются в undefined перед выполнением кода. Мы объясним это позже.

Что, если внутри есть функции, использующие переменные и параметры?

Есть ли у него контекст выполнения? Да!.

Это отдельныйконтекст выполнения? Да!

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

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

Поэтому два контекста выполнения — Global и Function контексты выполнения.

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

Один файл .js = одна глобальная область = один глобальный контекст выполнения (GEC)

Как насчет выделения памяти для функций?

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

Давайте посмотрим на пример здесь,

index.js  var a = 10; //first line 
var b = 'Javascript'; //second line  
//Declaring function 
function Test(x){ 
return x; 
};  
var c = Test('execution');

При запуске index.js создается глобальный контекст выполнения.

ГЭК:

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

Когда выполнение кода сталкивается с вызовом функции — Test(‘execution’). Он создает контекст выполнения функции для теста.

ФЭК

Расположение FEC поверх GEC называется стеком выполнения или стеком вызовов.

Что делать, если есть вложенные функции, такие как обратные вызовы?

function foo(x) { 
return x 
}  
function bar(x){ 
foo(x) 
};  
function baz(x){ 
bar(x) 
};  
baz('Hello from foo');//Hello from foo

Стек вызовов/стек выполнения = порядок обработки контекстов выполнения

Давайте определим undefined на этапе создания памяти:

Мы знаем, что все объявленные переменные сначала будут присвоены undefined в фазе памяти контекста выполнения. Это назначение является поведением по умолчанию даже до фактического выполнения кода.

Например,

// We can console the variable even before it is declared without any error  
console.log(a); 
var a = 10;

Перед выполнением кода переменной "a" присваивается значение undefined в фазе памяти контекста выполнения. Поэтому приведенный выше код приводит к

undefined --> without any error

Если var ‘a’ не объявлен, что может быть ошибкой?

console.log(a);

Это дает справочную ошибку, подобную этой.

ReferenceError: a is not defined

Таким образом, не определено и не определеноразличны, по крайней мере, в словаре JavaScript.

Эта идея фазы создания памяти в контексте выполнения перед фазой выполнения кода называется "Подъем".

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

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

Углубленное изучение масштабов!

Мы проиллюстрируем это,

  • Здесь var a имеет глобальное значение index.js. Он доступен как для первой, так и для второй функции.
  • Функция доступна для 'a', но не для 'c' и 'd'.
  • Вторая функция может получить доступ к a и b, а также ко всем переменным, доступным родительским функциям и глобальной области видимости.

Какую ошибку мы получим, если попытаемся получить доступ к ‘c’ или ‘d’ в глобальном масштабе?

Это не определено или не определено? Сделайте паузу и задумайтесь!

Что ж, ответ

ReferenceError: c is not defined

Почему? Каждая функция будет создавать отдельные контексты выполнения в стеке вызовов. У каждого есть своя фаза памяти и кода.

Когда вы создаете вложенные функции, как показано выше, стек вызовов будет,

Два FEC имеют доступ как к одному FEC, так и к одному GEC. Эта идея ограничения доступа к внешним функциям называется Closures.

Закрытие = доступ к внешним областям.

Замыкания используются во вложенных функциях или обратных вызовах.

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

Прежде чем продолжить, давайте подведем итоги.

  • JS — это однопоточный синхронный язык — одна задача за раз в последовательности.
  • Код JS реализуется в два этапа: этап памяти и этап исполнения кода.
  • Сначала происходит фаза памяти, а затем происходит выполнение кода.
  • Эти два события происходят в среде, называемой «Контекст выполнения».
  • Контекст выполнения может быть глобальным или функциональным контекстом выполнения. (GEC и FEC).
  • Переменные и функции перемещаются в верхнюю часть области видимости на этапе создания памяти. Эта концепция называется "Подъем".
  • Порядок контекста выполнения в стеке называется стеком выполнения или стеком вызовов.
  • Когда вы вкладываете функции, внутренние функции будут иметь доступ ко всей области действия внешней функции. Это называется Замыкания.

Последствия:

Давайте углубимся в var.

Область действия переменной:

var a = 1; 
console.log(a) // prints 1 because var 'a' is global scoped 
function print() { 
var a = 2; 
console.log(a); // prints 2 because var 'a' is function scoped 
};

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

var say = 'Hello'  
function name() { 
var person = 'John' 
console.log(`${say} ${person}`) //Prints Hello John 
}
name();  
console.log(person) // Error: var person is not defined --> person is in FEC name and it is available only to function name.
Hoisting implementation 
console.log(a) 
var a = 1;  
is interpreted as
 
var a = undefined; //First memory phase in EC 
console.log(a); // prints undefined because of previous step --> This is hoisting. 
a = 1 // Now assignment takes place in the code execution phase in EC

Реальная проблема с Var:

Мы знаем, что есть два контекста выполнения — один для Global (который охватывает весь файл .js) и для каждой функции (как только функция выполняется, она удаляется из стека вызовов).

Это означает, что помимо переменных внутри области действия (FEC) — все остальные вещи, такие как if..else, try..catch, будут подпадать под глобальную область видимости (GEC). В основном это две области.

var a = 1; 
var b = true; 
console.log(a); prints 1 because Global scope  
if(y) { 
var a = 2; 
} 
console.log(a)  
// prints 2 because values of var 'a' has been changed within the global context - no new execution context is created for 'if' statements unlike 'functions'.

В одном и том же контексте выполнения объявление var можно изменить.

Var может быть изменен или обновлен.

Во время подъема var инициализируется значением undefined. Мы можем получить к нему доступ до инициализации.

Большие приложения имеют много переменных, операторов if, try-catch и т. д. Мы можем случайно использовать одно и то же имя переменной, например var ‘a’ в приведенном выше примере. Это может иметь непредвиденные последствия в нашем коде, которые могут повлиять на приложение в целом.

Таким образом, объявление var имеет две проблемы:

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

Рождение let и const:

const заботится о проблеме изменения, а let заботится о проблеме области видимости. На самом деле, у обоих есть новая область действия, называемая 'Блочная область', и сначала они не инициализируются как неопределенные.

Но подождите. Что здесь заблокировать?

Блок = все, что заключено в { }

if { 
// it is a block 
} 
else { 
// it is a block 
}  
try { 
// it is a block 
} 
catch { 
// it is a block 
}

Например,

console.log(a); //  Cannot access 'a' before initialization  
const a = 1; // Assignment with const  
a = 2; // TypeError: Assignment to constant variable.  
const a = 2; // SyntaxError: Identifier 'a' has already been declared
console.log(a); //  Cannot access 'a' before initialization 
 
let a = 1; // Assignment with let 
 
a = 2;  ***//Accepts this assignment operation ***  
let a = 2; //SyntaxError: Identifier 'a' has already been declared

Мы можем сделать вывод, что constне может изменить свое значение после объявления, в то время как letможет изменить свое значение после объявления.

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

Как насчет области действия блока в let и const?

Блок = все, что находится внутри двух фигурных скобок { }. Следовательно, это включает функции.

const a = 1; 
let b = 1;  
if(true) { 
...block starts
  
const a =2; 
console.log(a) // Prints 2 because of block scope for const.  
let b = 3; 
console.log(b) // Prints 3 because of block scope for let.  block 
end... 
}  
// Within the block, there must not be the same variable names!!  function testing () { 
const a =2; 
console.log(a) // Prints 2 because of block scope for const.  
let b = 3; 
console.log(b) // Prints 3 because of block scope for let.
 }

Подняты ли параметры let и const?

Да! Они подняты — перемещены в верхнюю часть области, но не инициализированы до значения undefined. По этой причине вы получаете "невозможно получить доступ до инициализации". Если он не поднят, он будет «не определен».

Первоначально опубликовано на https://www.pansofarjun.com 4 сентября 2022 г.