Why is TypeScript generating an IIFE for a class?

2019-02-09 11:55发布

This question already has an answer here:

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?

2条回答
唯我独甜
2楼-- · 2019-02-09 12:15

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.

查看更多
啃猪蹄的小仙女
3楼-- · 2019-02-09 12:29

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

查看更多
登录 后发表回答