JavaScript: пожалуйста, объясните это странное поведение - PullRequest
2 голосов
/ 03 мая 2020

Только что начал изучать JS.

CASE-1 Пожалуйста, посмотрите на приведенное ниже изображение.

image 1

Мое понимание этого поведения : JS интерпретатор при достижении строки 9, какой команды для выполнения функции a (); создаст новый контекст выполнения для функции a (или мы можем сказать, выделить память в куче для контекста выполнения, который является объектом, и указать это на него, верно ??). Теперь я знаю, что интерпретатор сначала go пройдет через все тело функции и выделит место для объявлений переменных и функций в контексте выполнения, созданном в куче. Это видно из правой части изображения, где в локальной области видимости мы имеем ссылочную переменную b для лямбда-функции. И теперь после прохождения всего тела функции интерпретатор выполнит код. Теперь, поскольку у нас уже есть функция b , хранящаяся в контексте выполнения a (или контекст выполнения a знает о b ) , он выполнит это. (Это то, что подъем, верно ??) Пока все хорошо. Но,

Теперь посмотрите на это изображение:

Теперь, если в соответствии с моими концепциями, о которых я упоминал выше, с правой стороны внутри Local мы должны иметь переменную b , ссылающуюся на Функция лямбда, но это не так.

Что мне не хватает ?? Мои концепции неверны ?? Это из-за Chrome консоли ?? Можете ли вы объяснить это поведение ??

enter image description here

CASE-2 : Хорошо, тогда я провел другой эксперимент, чтобы узнать поведение интерпретатора :

enter image description here enter image description here

На обоих приведенных выше изображениях у нас есть пространство, выделенное для переменной a ссылка на лямбду функции, в обоих случаях. Это полностью противоположное поведение для случая 1.

Можете ли вы объяснить это поведение ??

Малый запрос (Если вы можете ..): Если вы можете использовать термины стек / куча / память / контекстный объект / ссылка / указатели выполнения вместо среды Lexical, областей видимости, замыканий, цепочки и т. д. c и c будет гораздо предпочтительнее, поскольку все они весьма запутаны. Мне легко понять вещи, используя вышеупомянутые термины.

1 Ответ

1 голос
/ 09 мая 2020

Ничего странного здесь нет. V8 компилирует JavaScript непосредственно в машинный код. В результате недоступный код, такой как функция b, удаляется, когда на него никогда не ссылаются. Это общее свойство почти каждого компилятора.

Что мне не хватает ?? Мои концепции неверны ?? Это из-за консоли Chrome ?? Можете ли вы объяснить это поведение ??

В этом фрагменте кода, который отличается от указанного в примере case-1 c, а именно в том, что был удален вызов b, b функция была удалена компилятором. В результате вы не видите никаких ссылок на него в отладчике.

case-2

При рассмотрении case-2 вы игнорируете тот факт, что отладчик остановлен не в том месте, чтобы проанализировать внутреннюю область действия function a. В результате вы видите a в окне отладки, и это все.

Ваша секция понимания

JS интерпретатор при достижении строки 9 какие команды для выполнения функции a (); создаст новый контекст выполнения для функции a (или мы можем сказать, выделить память в куче для контекста выполнения, который является объектом, и указать на него, верно ??)

Не совсем.

  • строка 9: выполнить функцию a () [правильно]
  • создать контекст выполнения для функции a [правильно]
  • выделить память в куче [неправильно]
  • контекст выполнения - это объект [правильно]
  • указывает на это [неправильно]

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

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

Это неверно. Как уже отмечалось, интерпретатор работает над скомпилированным кодом. Этот код уже имеет установленный объем памяти. В куче создается указатель, который указывает на скомпилированный код в стеке.

Это видно из правой части изображения, где в локальной области видимости у нас есть ссылочная переменная b к лямбда-выражению функция.

b не является лямбда-функцией, это было бы var b = () => console.log('Hello i am B');, и не было бы поднято. Помимо этого, a - это просто вложенный контекст. b также скомпилирован, и его ссылка c stati является просто компонентом уже скомпилированного a. Область видимости и хранение в памяти - это две совершенно разные концепции.

И теперь, после прохождения всего тела функции, интерпретатор выполнит код. Теперь, поскольку у нас уже есть функция b, хранящаяся в контексте выполнения a (или контекст выполнения a знает о b), она выполнит ее. (Вот что такое подъем, верно ??)

Этот код является прямым, поэтому интерпретатор создает указатель на кучу и немедленно выполняет скомпилированный код в стеке. a выполняется, затем внутри a, b выполняется, как отмечено выше.

Подъем - это просто перемещение объявлений в верхнюю часть областей для объявлений function и var, но не const или let. Подъем просто делает ваш первый пример эквивалентным этому:

function a(){
    function b(){
        console.log('Hello i am B')
    }
    console.log('Heloo')
    b()
}
a()
...