Inner functions and outer 'this' (Re: That hash symbol)
Mike Samuel
mikesamuel at gmail.com
Sat Mar 26 10:24:55 PDT 2011
2011/3/26 Claus Reinke <claus.reinke at talk21.com>:
>> We spent time yesterday at the TC39 meeting not only on shorter
>> syntax but exactly how to support better |this| handling for several
>> distinct use-cases: inner functions that want the outer |this|,
>> callbacks that want a certain |this|, and object methods that
>> want the receiver when called as methods of a given (receiver)
>> object (else possibly a default such as the outer function's |this|).
>
> That reminds me of an old solution looking for this problem.
>
> Back in 1976, Klaus Berkling suggested to complement the
> lambda calculus with an operator to protect variables from
> the nearest enclosing binding [1].
>
> The idea is simply that (lexically scoped) variables usually
> are bound to the next enclosing binding of the same name,
> while protected (lexically scoped) variables are bound to
> the next _outer_ enclosing binding of the same name
> (each protection key skips one level of binding, lexically).
>
> If I may use '#' as a placeholder for a suitable protection
> key, then this translates to Javascript as
>
> function Outer() {
> var x = "outer";
> function Inner() {
> var x = "inner";
>
> log(x); // "inner"
> log(#x); // "outer"
> log(##x); // global scope, probably unbound
> }
> }
To clarify, if I have the code
foo(#x)
and suddenly I realize that I need a to guard it with a condition,
if (bar) {
foo(#x)
}
this would ?not? change the binding of #x since, although I have
introduced a new let scoped block, x is not declared in that scope so
it is not counted against the stack of #'s.
It is not always easy to count scopes though without knowing a lot of
details. E.g. changing
function f() {}
(function () {
function () {
return f;
}
})()
requires two hashes
function f() {}
(function () {
function f() {
return ##f;
}
})()
since f was introduced both into the body scope, and into the outer
scope via the function declaration.
It seems brittle, and it seems that overloading labels to name scopes
would provide a less brittle alternative if this really is desired.
myScopeName: {
let x;
function f(x) {
g(x + myScopeName.x);
}
}
More information about the es-discuss
mailing list