Reaching the Outer Object from a Nested Method
An old caperjs refactor and the `this` chain that wasn't.
~/posts/this-chained $ cat post.md
The problem
Refactoring caperjs, I ran into this shape:
let a = {
b: 1,
c: {
d: function () {
return this;
},
e: function () {
console.log(b);
},
},
};
What I wanted was a.c.d().e() to log b. Inside d, this is c,
and c is a sibling of b — so to reach b I’d need to first reach
a. If this could chain one level further, this.this.b would do
it.
But this.this in JS isn’t Swift’s self.self. It evaluates to
this['this'], and c has no property called 'this'.
Attempt: a closure
Turn c into a function and stash this in a local for the inner
methods:
let a = {
b: 1,
c: function () {
let that = this;
return {
d: function () {
return this;
},
e: function () {
console.log(that.b);
},
};
},
};
But the call site becomes a.c().d().e() — one extra pair of parens
that wasn’t there before.
With fresh eyes
The actual problem isn’t this; it’s the bare b reference inside
e. There’s no b in scope there, so it would throw
ReferenceError. Give it a name it can resolve:
let a = {
b: 1,
c: {
d() {
return this;
},
e() {
console.log(a.b);
},
},
};
a.c.d().e(); // 1
e is called later, by which point a is fully bound, so referring to
a by name works fine. No this chain, no extra function — just make
the dependency on the outer object explicit.