back to index

Reaching the Outer Object from a Nested Method

An old caperjs refactor and the `this` chain that wasn't.

published Aug 09, 2017 tags #javascript #scope

~/posts/this-chained $ cat post.md

/ LANG EN / 中文
/ THEME / /

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.

back to index