Javascript function scoping and hoisting

后端 未结 18 3005
孤街浪徒
孤街浪徒 2020-11-21 04:20

I just read a great article about JavaScript Scoping and Hoisting by Ben Cherry in which he gives the following example:

var a = 1;

function b() {
    a =          


        
18条回答
  •  鱼传尺愫
    2020-11-21 05:13

    Suprisingly, none of the answers here mention the relevancy of the Execution Context in the Scope Chain.

    The JavaScript Engine wraps the currently executing code in an Execution Context. The base execution context is the global Execution Context. Each time a new function is invoked, a new Execution Context is created and put on the Execution Stack. Think of a Stack Frame sitting on an Invocation Stack in other programming languages. Last in first out. Now each Execution Context has its own Variable Environment and Outer Environment in JavaScript.

    I will use the below example as a demonstration.

    1) First, we enter the Creation Phase of the global Execution Context. Both the Outer Environment and Variable Environment of the Lexical Environment are created. The Global Object is setup and placed in memory with the special variable 'this' pointing to it. The function a and its code and the variable myVar with an undefined value are placed in memory in the global Variable Environment. it's important to note that function a's code is not executed. It is just placed in memory with function a.

    2) Second, it is the Execution Phase of the Execution Context. myVar is no longer an undefined value. It is initialized with value of 1, which is stored in the global Variable Environment. The function a is invoked and a new Execution Context is created.

    3) In the function a's Execution Context, it goes through the Creation and Execution Phase of its own Execution Context. It has its own Outer Environment and Variable Environment, thus, its own Lexical Environment. The function b and the variable myVar are stored in its Variable Environment. This Variable Environment is distinct from the global Variable Environment. Since the function a sits lexically (physically in code) on the same level as the global Execution Context, its Outer Environment is the global Execution Context. Thus, if the function a was to refer to a variable that is not in its Variable Environment, it will search the Scope Chain and try to find the variable in the Variable Environment of the global Execution Context.

    4) The function b is invoked in function a. A new Execution Context is created. Since it sits lexically in function a, its Outer Environment is a. So when it references myVar, since myVar is not in function b's Variable Environment, it will look in function a's Variable Environment. It finds it there and console.log prints 2. But if the variable was not in function a's Variable Environment, then since function a's Outer Environment is the global Execution Context, then the Scope Chain will continue searching there.

    5) After function b and a are finished execution, they are popped from the Execution Stack. The single-threaded JavaScript Engine continues execution at the global Execution Context. It invokes the b function. But there is no b function in the global Variable Environment and there is no other Outer Environment to search in the global Execution Context. Thus an exception is raised by the JavaScript Engine.

    function a(){
      function b(){
        console.log(myVar);
      }
    
      var myVar = 2;
      b();
    }
    
    var myVar = 1;
    a();
    b();
    > 2
    > Uncaught ReferenceError: b is not defined
    

    The below example shows the Scope Chain in action. In the function b's Execution Context's Variable Environment, there is no myVar. So it searches its Outer Environment, which is the function a. The function a does not have myVar in its Variable Environment either. So the Engine searches function a's Outer Environment, which is the global Execution Context's Outer Environment and myVar is defined there. Hence, the console.log prints 1.

    function a(){
      function b(){
        console.log(myVar);
      }
    
      b();
    }
    
    var myVar = 1;
    a();
    > 1
    

    Regarding Execution Context and the Lexical Environment associated with it, including Outer Environment and Variable Environment, enable the scoping of variables in JavaScript. Even if you invoke the same function multiple times, for each invocation, it will create its own Execution Context. So each Execution Context will have its own copy of the variables in its Variable Environment. There is no sharing of variables.

提交回复
热议问题