简体   繁体   中英

Scope of Default function parameters in javascript

I'm playing with some EcmaScript 2015 features and I must say that specification is rather hard to understand.

I totally understand that this code should throw error of some kind:

(function(a = b, b = 1) { })();

And I know that default value could use outer scope:

(function() {
  let c = 1;
  return (function(a = c) { return a === 1; })();
})();

But I don't understand why these examples are not good:

(function() {
  let a = 1;
  (function(a = a) { })();
})();

(function() {
  let b = 1;
  (function(a = b, b = 2) { })();
})();

My Chrome 59.0.3071.115 throws ReferenceError that variable is not defined.

It seems that Chrome is doing some optimization where only 1 scope is created where all parameters set as inaccessible, and they are added one by one after their assignment.

Some proof of this could be:

(function(a = () => b, b = 2) { return a() === 2; })();

This looks like an missing opportunity for my taste and I'm wondering does specification force to use only 1 scope here or this is only v8 implementation details.

Could somebody please point me to place in specification which could clarify this?

I don't understand why these examples are not good

Because the default initialisers are not evaluated in the parent scope, but rather inside the function scope. The parameters themselves are already in scope, so that you can do something like

(function(a = 2, b = a) { console.log(b); }());

Could somebody please point me to place in specification which could clarify this?

The relevant section is §9.2.12 FunctionDeclarationInstantiation .

I must say that specification is rather hard to understand.

Yes it is, although it's written for engine implementors not for programmers. However, the explanatory note basically confirms your understanding of the optimisation

If the function's formal parameters do not include any default value initializers then the body declarations are instantiated in the same Environment Record as the parameters. If default value parameter initializers exist, a second Environment Record is created for the body declarations.

Your examples basically desugar to

(function() {
  let a = arguments[0] !== undefined ? arguments[0] : b,
//                                                    ^ clearly a ReferenceError
      b = arguments[1] !== undefined ? arguments[1] : 1;
  {
  }
})();

(function() {
  let c = 1;
  return (function() {
    let a = arguments[0] !== undefined ? arguments[0] : c;
//                                                      ^ works as you'd think
    {
      return a === 1;
    }
  })();
})();

(function() {
  let a = 1;
  (function() {
    let a = arguments[0] !== undefined ? arguments[0] : a;
//                                                      ^ again clearly a ReferenceError
    {
    }
  })();
})();

(function() {
  let b = 1;
  (function() {
    let a = arguments[0] !== undefined ? arguments[0] : b,
//                                                      ^ still a ReferenceError
        b = arguments[1] !== undefined ? arguments[1] : 2;
    {
    }
  })();
})();

(function() {
  let a = arguments[0] !== undefined ? arguments[0] : () => b,
//                                                          ^ works indeed
      b = arguments[1] !== undefined ? arguments[1] : 2;
  {
    return a() === 2;
  }
})();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM