Search code examples
javascriptscopeexecutioncontext

JavaScript : Please Explain this weird behaviour


Just Started learning about JS.

CASE-1 Please look at the below given image.

image 1

My Understanding for this behavior : 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 ??). 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. 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 ??) So far so good. But,

Now look at this image :

Now if according to my concepts which i mentioned above, On right side inside Local we must have a variable b referencing to function lambda, but its not.

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

enter image description here

CASE-2 : Ok Then i did another experiment to know the behavior of Interpreter :

enter image description here enter image description here

In both of the above given images, we have space allotted to variable a referencing to lambda of function, in both cases. This is completely opposite behavior to case-1.

Can you explain this behavior ??

Small Request (If you can..): If you can use the terms stack/heaps/memory/execution context object/link/pointers instead of Lexical environment, scopes, closures, chain etc etc it will be much preferred since they all are quite confusing. Its easy for me to understand things using above mentioned terms.


Solution

  • Nothing strange here. V8 compiles JavaScript directly into machine code. As a result, unreachable code, such as function b, is removed when it is never referenced. This is a common property of almost every compiler.

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

    In this code snippet, which is different than the specific example of case-1, namely in that the call to b has been removed, the b function has been removed by the compiler. As a result, you do not see any reference to it in the debugger.

    case-2

    In your examination of case-2, you overlook the fact that the debugger is stopped in the wrong place to analyze the interior scope of function a. As a result, you see a in the debugging window and that is it.

    Your understanding section

    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 ??)

    Not entirely.

    • line 9: execute function a() [correct]
    • create an execution context for function a [correct]
    • allocate memory in heap [incorrect]
    • execution context is an object [correct]
    • point this to it [incorrect]

    The execution context is an object, however, the compiled function is a static function frame stored on the stack. The this binding is a separate value which does not reference the execution context, but instead provides an entrance for variable scoping.

    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 incorrect. As noted, the interpreter is working on compiled code. This code already has an established memory footprint. A pointer is created on the heap which points to the compiled code in the stack.

    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 is not a lambda function, that would have been var b = () => console.log('Hello i am B');, and would not have been hoisted. That aside, under the hood, a is just a nested context. b is also compiled, and its static reference is just a component of the already compiled a. Scoping and memory storage are two very different concepts.

    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 ??)

    This code is direct, so the interpreter would create a pointer on the heap, and immediately execute the compiled code on the stack. a is executed, then inside of a, b is executed as noted above.

    Hoisting is simply moving declarations to the tops of scopes for function declarations and var declarations, but not const or let. Hoisting simply makes your first example equivalent to this:

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