We've agreed to change the way this is propagated in calls to lexically nested functions (http://wiki.ecmascript.org/doku.php?id=proposals:bug_fixes, http://wiki.ecmascript.org/doku.php?id=es3.1:inner_functions_and_this). What remains is to agree about some of the details.
There are two cases: function definitions and function expressions.
(1) Definitions: My understanding is that if
- there is a FunctionDefinition of a function f,
- that definition is lexically nested inside any other function definition or expression (including methods), and
- the calling code calls f directly by name as in f(...)
then the value of this is propagated. Examples:
function g() {
function f() { return this }
f()
}
function h() {
function f() { return this }
function m() { return f() }
m()
}
Note f need not be defined inside its caller, it can be a peer of the caller (as in the second example), a peer of the caller's enclosing function, or indeed one of the functions enclosing the caller. The only requirement is that f is not a top-level function (ie, defined in Program, Package, or Class scope).
Expressions: There are two cases, named and unnamed.
(2a) Named expressions. Consider this code:
function g() {
var v = function f() { ... f() ... }
v()
var o = { f: v }
o.f()
}
Here it seems to me that the call through v should pass the global object as this but that the recursive call to f should probably propagate the value of this, as motivated by the call to o.f. This case is not covered by the three conditions above, so we get a fourth:
- If f is a named FunctionExpression containing a recursive call to itself by its given name, then that recursive call propagates the value of this.
(2b) Unnamed expressions. Consider the following program:
function g() {
print( function () { return this } () )
let x = function () { return this }
print( x() )
}
By the previous argument, the call through x should pass the global object as this. My argument is that the second part of g is a simple refactoring of the first part, therefore the first part should have the same result, therefore direct calls to function expressions (named or unnamed) should not propagate this.
Note that:
- direct calls to function expressions will be much less common in idiomatic ES4 than in ES3
- it's not obvious that propagating this to direct calls to function expressions is all that useful in practice
Note also that:
- in all cases, whether the variable f is mutable or not (or may have been mutated or not) is not taken into account.
- with does not figure into the equation, because if a variable is looked up and found to be bound by a with object then that object is the this value.