JavaScript : 请解释这个奇怪的行为

JavaScript : Please Explain this weird behaviour

刚开始学习 JS。

CASE-1请看下图

我对此行为的理解:JS 解释器到达第 9 行时命令执行函数 a();将为函数 a 创建一个新的执行上下文(或者我们可以说在堆中为执行上下文分配内存,这是一个对象并指向 this 到它, 正确的 ??)。现在我知道解释器将首先遍历整个函数体,并在堆中创建的执行上下文中为变量声明和函数声明分配 space。从图像的右侧可以明显看出,在局部作用域中,我们有一个指向函数 lambda 的引用变量 b。现在,在通过整个函数体之后,解释器将执行代码。现在,由于我们已经将函数 b 存储在 a 的执行上下文(或 a 的执行上下文中执行上下文知道 b),它将执行它。 (这就是提升,对吧??) 到目前为止,一切都很好。但是,

现在看这张图片:

现在如果根据我上面提到的概念, 在 Local 的右侧,我们必须有一个引用函数 lambda 的变量 b,但它不是。

我错过了什么?? 我的观念错了吗?? 是因为 Chrome console 吗?? 你能解释一下这种行为吗??

CASE-2:好的然后我做了另一个实验来了解解释器的行为:

在上面给出的两个图像中,在这两种情况下,我们都将 space 分配给引用函数 lambda 的变量 a。这与案例 1 完全相反。

你能解释一下这个行为吗??

Small Request (If you can..): 如果你可以使用术语 stack/heaps/memory/execution 上下文 object/link/pointers 而不是词法环境、范围、闭包、链等,那将是更受欢迎的,因为他们都很混乱。使用上述术语对我来说很容易理解。

没什么奇怪的。 V8 将 JavaScript 直接编译成机器码。结果,无法访问的代码(例如函数 b)在从未被引用时被删除。这是几乎每个编译器的共同点 属性。

What am i missing ?? Is my concepts wrong ?? Is it because of Chrome console ?? Can you explain this behavior ??

在这个代码片段中,与案例 1 的具体示例不同,即对 b 的调用已被删除,b 函数已被编译器删除.因此,您在调试器中看不到对它的任何引用。

case-2

在检查案例 2 时,您忽略了调试器在错误的位置停止以分析 function a 的内部范围这一事实。结果,您在调试 window 中看到 a 就是这样。

你的理解部分

JS interpreter on reaching line 9 which commands to execute function a(); will create a new execution context for function a (or we can say allocate memory in heap for execution context which is an object and point this to it, right ??)

不完全是。

  • 第 9 行:执行函数 a() [正确]
  • 为函数a创建执行上下文[正确]
  • 在堆中分配内存[不正确]
  • 执行上下文是一个对象[正确]
  • 指向它[不正确]

执行上下文是一个对象,但是编译后的函数是一个静态的函数帧,存储在栈中。 this 绑定是一个单独的值,它不引用执行上下文,而是为变量范围提供入口。

Now i know that interpreter will first go through the whole function body and will allocate space for variable declarations and function declaration, in the execution context created in heap.

这是不正确的。如前所述,解释器正在处理编译后的代码。此代码已经具有确定的内存占用空间。在堆上创建一个指针,指向堆栈中的编译代码。

This is evident from the right side of the image where in local Scope we have a reference variable b to the lambda of function.

b 不是 lambda 函数,它应该是 var b = () => console.log('Hello i am B');,并且 不是 。除此之外,在幕后,a 只是一个嵌套的上下文。 b也被编译了,它的静态引用只是已经编译的a的一个组成部分。作用域和内存存储是两个截然不同的概念。

And now after having a pass through whole function body interpreter will execute code. Now since we already have the function b stored in a's execution context (or a's execution context knows about b),it will execute it. (This is what hoisting is, right ??)

这段代码是直接的,所以解释器会在堆上创建一个指针,并立即在堆栈上执行编译后的代码。 a 被执行,然后在 a 内部,b 如上所述被执行。

提升只是将声明移动到 function 声明和 var 声明的范围顶部,而不是 constlet。提升只是让你的第一个例子等同于:

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