为什么TypeScript会为类生成IIFE?

Tar*_*ion 8 javascript class typescript

看看这个TypeScript代码:

class Greeter {
    greet() {}
}
Run Code Online (Sandbox Code Playgroud)

它围绕构造函数和所有原型函数声明生成一个IIFE(立即调用的函数表达式),如:

var Greeter = (function () {
    function Greeter() {
    }
    Greeter.prototype.greet = function () { };
    return Greeter;
}());
Run Code Online (Sandbox Code Playgroud)

这有什么好处?当我读到IIFE时,我发现定义模块有很多用处.据我所知,Typescript不会在IIFE中生成会污染全局命名空间的任何内容.

在我看来,这个类宣言没有任何优势:

var Greeter = function () {}
Greeter.prototype.greet = function () { };
Run Code Online (Sandbox Code Playgroud)

它是什么原因?

Man*_*mar 9

避免全局命名空间污染.

它是一种clousure模式,其中内部函数可以访问其父项属性.通过IIFE,返回内部函数的参考.

下面是两个场景,其中IIFE模式非常有用,原因是TypeScript Compiler生成IIFE模式的原因:

  1. 继承实现:它将BaseClass作为参数传递给IIFE的地方.如果IIFEE不存在,BaseClass那么将存在全局变量,从而污染全局命名空间.

TypeScript:

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

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));
Run Code Online (Sandbox Code Playgroud)
  1. 模块模式实现:其中,app只有一个全局变量等"应用"和所有其它的特征被包裹成对象等app.cart,app.catalog等有唯一的变量是通过模块暴露和所有其它的功能被添加到模块本身,这是能够通过IIFE只要.

TypeScript:

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

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 = {}));
Run Code Online (Sandbox Code Playgroud)

将此js代码复制/粘贴到浏览器控制台,仅全局创建App变量.休息功能将在App下.

谢谢,mkdudeja


Tam*_*dus 6

这太有趣了.我认为typescript编译器通过将表达式赋值给范围中的变量来编译ClassDeclarationClassExpressions 推导出来,因此他们不必独立处理这些情况.这简化了TypeScript编译器,并使生成的代码有点模块化(我想说更具可读性,但这只是一个品味问题).

class Bar { };
foo(class Baz { });
var Baa = class Bab { };
Run Code Online (Sandbox Code Playgroud)

编译成:

var Bar = (function () {
    function Bar() {
    }
    return Bar;
}());
;
foo((function () {
    function Baz() {
    }
    return Baz;
}()));
var Baa = (function () {
    function Bab() {
    }
    return Bab;
}());
Run Code Online (Sandbox Code Playgroud)

看,ClassDeclaration编译为ClassExpression分配给局部变量.