Daud
Daud

Reputation: 7897

Till what level do closures keep their execution contexts?

Functions returning from a method keep a copy of their parent execution context, and this is called closure. But what if the function is inside another function which is inside another function like this:

const a = function() {
    const aa = 'aa';
    return function() {
        const bb = 'bb';
        return function() {
            return aa;
        }
    }
}

Now, if I call it like:

a()()();

It'll return "aa" because the nexted-most method seems to have access to its grandparent context. So, do all inner methods keep the execution contexts of all their ancestors in which they're nested, when these inner methods are returned?

Upvotes: 1

Views: 88

Answers (2)

Yousaf
Yousaf

Reputation: 29354

Closure is just a reference to an environment in which a function is defined.

In the code example (I have given each function a name to make it easy to explain):

const a = function() {
    const aa = 'aa';
    return function b() {
        const bb = 'bb';
        return function c() {
            return aa;
        }
    }
}

function c will have a reference to the local scope of function b. Similarly, function b will have a reference to the local scope of function a.

This chain of references is what's known as a scope chain and Javascript will traverse this chain until it finds the identifier aa.

Reference to the environment in which a function is defined is saved in an internal slot which the Ecmascript specification calls the [[Environment]] slot of the function object.

Upvotes: 2

Quentin
Quentin

Reputation: 944568

So, do all inner methods keep the execution contexts of all their ancestors in which they're nested, when these inner methods are returned?

For almost all practical purposes: Yes.

JS engines do optimise though, so in practise only data that needs to be kept around is kept rather than the whole lexical environment.

For example, given:

const a = () => {
    const foo = 1;
    const bar = 2;
    const b = () => {
        console.log(foo);
        debugger;
    }
}

a()();

Most JS engines will make foo available to b but, because b doesn't use bar, they will discard bar and it won't be available to the debugger.

Upvotes: 3

Related Questions