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
声明的范围顶部,而不是 const
或 let
。提升只是让你的第一个例子等同于:
function a(){
function b(){
console.log('Hello i am B')
}
console.log('Heloo')
b()
}
a()
刚开始学习 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
声明的范围顶部,而不是 const
或 let
。提升只是让你的第一个例子等同于:
function a(){
function b(){
console.log('Hello i am B')
}
console.log('Heloo')
b()
}
a()