Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is TypeScript generating an IIFE for a class? [duplicate]

Looking at this TypeScript code:

class Greeter {
    greet() {}
}

It generates an IIFE (Immediately-Invoked Function Expression) around the constructor function and all prototype function declarations like:

var Greeter = (function () {
    function Greeter() {
    }
    Greeter.prototype.greet = function () { };
    return Greeter;
}());

What is the advantage here? When ever I read about IIFE I see a lot usage in defining modules. As far as I can see Typescript does not generate anything inside the IIFE that would pollute the global namespace.

In my opinion there is no advantage over this class declaration:

var Greeter = function () {}
Greeter.prototype.greet = function () { };

What is the reason for it?

like image 886
Tarion Avatar asked Mar 25 '16 09:03

Tarion


People also ask

What is the point of an IIFE?

An Immediately-invoked Function Expression (IIFE for friends) is a way to execute functions immediately, as soon as they are created. IIFEs are very useful because they don't pollute the global object, and they are a simple way to isolate variables declarations.

What is TypeScript IIFE?

An IIFE (Immediately Invoked Function Expression) is a JavaScript function that runs as soon as it is defined. The name IIFE is promoted by Ben Alman in his blog. (function () { // … })(); (() => { // … })(); (async () => { // …

How does IIFE work in JavaScript?

Immediately-Invoked Function Expressions (IIFE), pronounced "iffy", are a common JavaScript pattern that executes a function instantly after it's defined. Developers primarily use this pattern to ensure variables are only accessible within the scope of the defined function.

Which statement represents the starting code converted to an immediately invoked function expression IIFE?

(function () { })(); This is called IIFE (Immediately Invoked Function Expression).


2 Answers

To avoid global namespace pollution.

Its a clousure pattern where inner functions have access to their parents properties. By IIFE, REFERENCE to inner functions returned.

Below are two scenarios, where IIFE pattern is quite helpful and the reason, why TypeScript Compiler generates IIFE pattern:

  1. Inheritance implementation: where it passes the BaseClass as an argument to IIFE. If IIFEE would not have been there BaseClass would be global variable, thus polluting the global namespace.

TypeScript:

class Greeter extends BaseController {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}

JS:

var Greeter = (function(_super) {
    __extends(Greeter, _super);

    function Greeter(message) {
        this.greeting = message;
    }
    Greeter.prototype.greet = function() {
        return "Hello, " + this.greeting;
    };
    return Greeter;
}(BaseController));
  1. Module pattern implementation: where app has only one global variable like 'app' and all other features are wrapped into objects like app.cart, app.catalog etc. There only variable is exposed through modules and all other features are added to the modules itself, which is possible by IIFE only.

TypeScript:

module App.Controller {
    export class Greeter extends BaseController {
        greeting: string;
        constructor(message: string) {
            this.greeting = message;
        }
        greet() {
            return "Hello, " + this.greeting;
        }
    }
}

JS:

var App;
(function (App) {
    var Controller;
    (function (Controller) {
        var Greeter = (function (_super) {
            __extends(Greeter, _super);
            function Greeter(message) {
                this.greeting = message;
            }
            Greeter.prototype.greet = function () {
                return "Hello, " + this.greeting;
            };
            return Greeter;
        }(BaseController));
        Controller.Greeter = Greeter;
    })(Controller = App.Controller || (App.Controller = {}));
})(App || (App = {}));

Copy/Paste this js code to browsers console and only App variable will be globally created. Rest functionality will be under App.

Thanks, mkdudeja

like image 70
Manish Kumar Avatar answered Nov 15 '22 19:11

Manish Kumar


That is interesting. I think the typescript compiler compiles ClassDeclaration deduced from ClassExpressions, by assigning the expression to a variable in the scope, so they don't have to handle those cases independently. This simplifies the TypeScript compiler, and makes the generated code somewhat modular (I would say more readable, but that's just a matter of taste).

class Bar { };
foo(class Baz { });
var Baa = class Bab { };

Compiles into:

var Bar = (function () {
    function Bar() {
    }
    return Bar;
}());
;
foo((function () {
    function Baz() {
    }
    return Baz;
}()));
var Baa = (function () {
    function Bab() {
    }
    return Bab;
}());

See, the ClassDeclaration is compiled as a ClassExpression assigned to a local variable.

like image 43
Tamas Hegedus Avatar answered Nov 15 '22 21:11

Tamas Hegedus