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?
Yes, the parameter initializers are evaluated at call time. It's complicated, but the steps are basically as follows:
with a new environment in the "closure scope" of the called function
thisBindingis initialisedargumentsobject is created an boundIn the course of this, initialisers are evaluated
undefinedletandconstvariables in the function body are createdSo parameter initialisers do have access to the
thisand theargumentsof 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).Because
xis a local variable thatbardoes 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, thexidentifier is resolved to the globalxvariable.