Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does `this` work in default parameters?

So... ES6¹ (which happens to be standardized a few hours ago) brings default parameters for functions similar to those in PHP, Python etc. I can do stuff like:

function foo (bar = 'dum') {
    return bar;
}

foo(1); // 1
foo(); // 'dum'
foo(undefined); // 'dum'

MDN says that the default value for the parameter is evaluated at call time. Which means each time I call the function, the expression 'dum' is evaluated again (unless the implementation does some weird optimizations which we don't care about).

My question is, how does this play into this?

let x = {
  foo (bar = this.foo) {
    return bar;
  }
}

let y = {
  z: x.foo
}

x.foo() === y.z(); // what?

The babel transpiler currently evaluates² it as false, but I don't get it. If they are really evaluated at call time, what about this:

let x = 'x from global';

function bar (thing = x) {
  return thing;
}

function foo () {
  let x = 'x from foo';
  return bar();
}

bar() === foo(); // what?

The babel transpiler currently evaluates³ it as true, but I don't get it. Why does bar not take the x from foo when called inside foo?

1 - Yes I know it is ES2015.
2 - Example A
3 - Example B

like image 938
user3459110 Avatar asked Jun 17 '15 20:06

user3459110


People also ask

How do default parameters work in Python?

In Python, a default parameter is defined with a fallback value as a default argument. Such parameters are optional during a function call. If no argument is provided, the default value is used, and if an argument is provided, it will overwrite the default value.

What are the parameters that are default?

The default parameter is a way to set default values for function parameters a value is no passed in (ie. it is undefined ). In a function, Ii a parameter is not provided, then its value becomes undefined . In this case, the default value that we specify is applied by the compiler.

What is default parameter explain with example?

A default argument is a value provided in a function declaration that is automatically assigned by the compiler if the calling function doesn't provide a value for the argument. In case any value is passed, the default value is overridden.

How does default parameters are given in a function prototype?

The default arguments are given in the function prototype. Compiler uses the prototype information to build a call, not the function definition. The default arguments are given in the function prototype and should be repeated in the function definition.


1 Answers

My question is, how does this play into this? I don't get it. Are they are really evaluated at call time?

Yes, the parameter initializers are evaluated at call time. It's complicated, but the steps are basically as follows:

  1. A new execution context is established on the stack,
    with a new environment in the "closure scope" of the called function
  2. If necessary, it's thisBinding is initialised
  3. Declarations are instantiated:
    1. Mutable bindings for the parameter names are created
    2. If necessary, an arguments object is created an bound
    3. The bindings are iteratively initialised from the arguments list (including all destructurings etc)
      In the course of this, initialisers are evaluated
    4. If any closures were involved, a new environment is inserted
    5. Mutable bindings for the variables declared in the function body are created (if not already done by parameter names) and initialised with undefined
    6. Bindings for let and const variables in the function body are created
    7. The bindings for functions (from function declarations in the body) are initialised with instantiated functions
  4. Finally the body of the function is evaluated.

So parameter initialisers do have access to the this and the arguments of the call, to previously initialised other parameters, and everything that is in their "upper" lexical scope. They are not affected by the variables declared in the function body (though they are affected by all the other parameters, even if in their temporal dead zone).

what about this:

function bar (thing = x) {}
{
  let x = 'x from foo';
  return bar();
}

I don't get it. Why does bar not take the x from foo when called inside foo?

Because x is a local variable that bar does not have access to. We're so lucky that they are not dynamically scoped! The parameter initialisers are not evaluated at the call site, but inside the called function's scope. In this case, the x identifier is resolved to the global x variable.

like image 176
Bergi Avatar answered Sep 28 '22 01:09

Bergi