11

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?

M. Junaid Salaat
  • 3,765
  • 1
  • 23
  • 25
Tarion
  • 16,283
  • 13
  • 71
  • 107
  • Probably to simplify TypeScript's code so it doesn't have to guess when it needs an iife or not, that's the advantage. It doesn't really matter, does it? If this were hand written code, you'd have more of a point – Ruan Mendes Mar 25 '16 at 09:46
  • 2
    For the guys who voted to close this question: It's not opinion based. The TS compiler does it this way, and the question is why. I assume there is at least some reason behind this decision. – Tarion Mar 28 '16 at 06:16

2 Answers2

11

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

Manish Kumar
  • 1,131
  • 15
  • 28
  • 1
    OP stated that the code would not pollute the global namespace, and I dont see how would that pollute the global namespace either. Could you please clarify? – Tamas Hegedus Mar 25 '16 at 09:36
  • Just because the reference to the inner function is immediately assigned to a variable with the same name – Tamas Hegedus Mar 25 '16 at 09:37
  • If you are right, please find an example that would pollute the global namespace. All variable declarations of the class happen on the prototype. I read through the typescript class documentation and did not found anything. – Tarion Mar 28 '16 at 05:59
  • edited the post and added code snippets & explanations. – Manish Kumar Mar 28 '16 at 08:55
8

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.

Tamas Hegedus
  • 28,755
  • 12
  • 63
  • 97