Joel's dev blog

Scope and closure (6): Dynamic scope, Polyfilling Block Scope, and Lexical-this

April 08, 2018

2 min read

Dynamic scope

“Dynamic scope seems to imply, and for good reason, that there’s a model whereby scope can be determined dynamically at runtime, rather than statically at author-time.”

What’s important is where a function is called from. The scope chain is based on the call stack.

this

this is similar to dynamic scope in that it cares about how a function is called.

Try-catch instead of a block

in ES6:

function doSomethingWith(thing){
    // some useful calculations
}

{
    let someVariableToBeContained = 0;
    doSomethingWith(someVariableToBeContained);
}

doSomethingWith(someVariableToBeContained); // error

would just work. But before ES6:

function doSomethingWith(thing){
    // some useful calculations
}

try {
    throw 0;
}
catch(a){
     doSomethingWith(someVariableToBeContained);
}
doSomethingWith(someVariableToBeContained); // error

..yeah.

let block

let(sth = 0){
    console.log(sth);
}

// scope is limited to the inside of this (explicit) block.

but this is not supported by ES6 syntax. It needs a tool to convert itself. So just doing a normal block would be okay too.

Lexical-this

javascript had this problem that when you do not have favorable function scopes, this keyword could not be used except when you use something like var self = this.

ES6 solves this problem by the arrow function by introducing lexical-this. Below code is copied from YDKJS:

var obj = {
    count: 0,
    cool: function coolFn() {
        // no need for var self = this;
        if (this.count < 1) {
            setTimeout( () => { // arrow-function ftw?
                this.count++; 
                // you do not have to refer to self here anymore. 
                console.log( "awesome?" );
            }, 100 );
        }
    }
};

obj.cool(); // awesome?

And below code is more awesome because it shows our intention by adding bind().

var obj = {
    count: 0,
    cool: function coolFn() {
        if (this.count < 1) {
            setTimeout( function timer(){
                this.count++; // `this` is safe because of `bind(..)`
                console.log( "more awesome" );
            }.bind( this ), 100 ); // look, `bind()`!
        }
    }
};
obj.cool(); // more awesome

Written by Joel Mun. Joel likes Typescript, React, Node.js, GoLang, Python, Wasm and more. He also loves to enlarge the boundaries of his knowledge, mainly by reading books and watching lectures on Youtube. Guitar and piano are necessities at his home.

© Joel Mun 2023