This is a summary of the scope section in the ECMAScript 6 Getting Started function Parameter Defaults chapter, and looks at some related issues, as well as a translation issue with Babel.

Parameter default value and scope

Reference for this section:

  • Understanding the default values of es6 function parameters? Answer by dablwow80
  • ECMAScript introduction to 6
  • The third scope caused by the parameter default value
  • ECMAScript ® 2015 Language Specification
  • Js variable declaration function declaration variable assignment implementation mechanism doubt? – Answer to the aurora – Zhihu
  • Order of function execution

In the ECMA – 262 9.2.12 FunctionDeclarationInstantiation (func, argumentsList) chapter related instructions.

When parsing the execution context of a JS function, a new Environment Record (ER) is created and each instantiated parameter in the ER is bound. Each declaration in the function body is also instantiated.

  • If the parameters do not have any default values, the function body declaration is instantiated in the same ER as the parameters. That is, declarations in the body of a function are instantiated in the same ER as parameters.

    • Function parameters are added to the scope of the function, and the parameters are not redefined (using var to declare variables with the same name as the parameter is ignored).

      function fun(arg1, arg2) {
        var arg1; // The declaration is ignored
        var arg2 = "hello"; // var arg2 declaration is ignored and arg2 = "hello" is executed
        console.log(arg1, arg2);
      }
      fun(1.2); // 1 "hello"
      Copy the code
    • ES6 lets and const will report errors due to repeated declarations in scope

      function fun(arg) {
        let arg;
      }
      fun(); // SyntaxError: Identifier 'arg' has already been declared
      Copy the code
    • One more case is if a function is declared with the same name as the parameter

      Prior to ES6, the execution of a function could be divided into three stages (after ES6 things became more complicated and unknown) :

      • To prepare. This includes parameter creation, function body preresolving (var declaration and function declaration promotion, that is, reactive), and function declaration creation
      • Load, that is, populate data. Loading order isFunction parameters > Function declarationIf there is a function declaration in the function body with the same name as the parameter, the function overrides the parameter
      • Execution, slightly
      function fun(arg) {
        console.log(arg);
        function arg() {
          / /...
        }
      }
      fun(1); // [Function: arg]
      Copy the code
      • In preparation, create parametersarg, function body preparse, create function declaration
      • During the load phase, the parameter 1 is assigned toarg.arg = 1There is a function declaration in the function bodyfunction arg(){}, so the function specification is assigned toarg, that is,arg = function(){}

PS: The above cases are only summarized through performance and results, and are not analyzed strictly in accordance with the specifications. If you are wrong, please feel free to comment.

  • When a function is executed, if there is a default value for the function parameter, a second ER is created. This scope is for the declaration in the function body, so the declaration in the function body is not in the same scope as the function declaration of the parameter and itself

    So a function declaration with default parameters defined in a global environment generates at least three scopes at runtime, as shown below:

    • Variables in ER of a parameter can only read variables in ER or outside of the function. Variables in a function can read variables in a function, a parameter, and outside of the function

    • Inside a function, you can change the values of parameters defined in ER, but you cannot redefine parameters

      • withvarJust because a variable is declared as a Block does not mean it is block-level scoped, whileJust to distinguish parametersERAnd the body of the functionER

A question

var x = 20;
function fun(x = 1) {
  debugger;
  var x = 10;
  console.log(x);
}
fun(2);
Copy the code

Since the parameter scope and the function body scope do not share, why should a variable declared using var in the function body scope have an initial value that is the same as the value instantiated by the parameter?

I hope someone senior can answer my questions.

Analyze a few small examples:

  • Parameters are individually scoped

    let x = 1;
    function fun(x, y = x) {
      console.log(y);
    }
    fun(2);
    Copy the code
    • parameteryThe default value of thex
    • Call a functionfun, the parameter forms a separate scope
    • In this scope, the default value variable points to the first parameterx, not the global environmentx
  • Scopes created by parameters with default values also look for variables along the scope chain

    function fun(y = x) {
      let x = 2;
      console.log(y);
    }
    fun(); // ReferenceError: x is not defined
    Copy the code
    • Call a functionfunWhen the parametery=xForm a separate scope
    • In this scope, there is no definitionx, so look for variables globally along the scope chainx
    • There are no variables defined in the global environmentx, so an error will be reported
    • When a function is called, the local variable x inside the function body does not affect the parameter default variable x
  • Avoid temporary Dead Zones (TDZ)

    let x = 1;
    function fun(x = x) {}
    fun(); // Uncaught ReferenceError: x is not defined
    Copy the code
    • parameterx = xForm a separate scope
    • In this scope, the execution islet x = xThat’s how temporary death zones form

If the default value of the argument is a function, the scope of that function also follows the rules above

let foo = "outer";
function bar(func = () => foo) {
  let foo = "inner";
  console.log(func());
}
bar(); // outer
Copy the code
  • functionbarThe parameters of thefuncThe default value of is an anonymous function that returns a variablefoo
  • Parameters are formed in a separate scope, and no variables are definedfoo, so pointing to the outer global variablefoo

A Babel problem

Reference for this section:

  • Extensions to ES6 functions
  • Understanding the default values of es6 function parameters? Answer by dablwow80
  • Babel translation

In ruan yifong’s introduction to ECMAScript 6, there was an example of a complex parameter default that was translated by Babel to behave differently than before.

  • ES6

    var x = 1;
    function foo(
      x,
      y = function() {
        x = 2;
      }
    ) {
      var x = 3;
      y();
      console.log(x);
    }
    
    foo(); / / 3
    Copy the code
    • Since parameters have default values, the parameters of a function form a separate scope
    • yThe default value of is an anonymous function, a variable within the functionxThe first parameter pointing to the same scopex
    • An internal variable is also declared inside the function bodyx, the variable and the first parameterxIt is not the same variable because it is not the same scope
    • performyAfter, internal variables and external variablesxThe value of alpha is the same
  • After translation into ES5 ([email protected]), the result was found to be different from the original result. The reason is that the scope of the parameter and the function body is not separated after translation

    "use strict";
    var x = 1;
    function foo(x) {
      var y =
        arguments.length > 1 && arguments[1]! = =undefined
          ? arguments[1]
          : function() {
              x = 2;
            };
      var x = 3;
      y();
      console.log(x);
    }
    foo(); / / 2
    Copy the code
  • Modified based on Babel

    function foo(x) {
      var y =
        arguments.length > 1 && arguments[1]! = =undefined
          ? arguments[1]
          : function() {
              x = 2;
            };
      return function() {
        var x = 3;
        y();
        console.log(x);
      }.call(this, x, y);
    }
    Copy the code

Babel may not have changed it for some reason, but the result is that the translated code does not match the original result.

conclusion

In fact, I still find it difficult to analyze this problem. I cannot analyze the reason from ECMAScript® 2015 Language Specification, that is, I cannot fundamentally explain the complete operation principle. It’s more about learning from other people’s understanding.

In fact, this problem rarely appears in business scenarios and has more research significance than practical significance.

reference

  • Understanding the default values of es6 function parameters? Answer by dablwow80
  • ECMAScript introduction to 6
  • The third scope caused by the parameter default value
  • ECMAScript ® 2015 Language Specification
  • Js variable declaration function declaration variable assignment implementation mechanism doubt? – Answer to the aurora – Zhihu
  • Order of function execution