Почему TypeScript упаковывает класс в IIFE? - PullRequest
16 голосов
/ 11 мая 2019

Вот класс TypeScript:

class Greeter {
    public static what(): string {
        return "Greater";
    }

    public subject: string;

    constructor(subject: string) {
        this.subject = subject;
    }

    public greet(): string {
        return "Hello, " + this.subject;
    }
}

Он переносится в IIFE, когда TS нацеливается на ES5:

var Greeter = /** @class */ (function () {
    function Greeter(subject) {
        this.subject = subject;
    }
    Greeter.what = function () {
        return "Greater";
    };
    Greeter.prototype.greet = function () {
        return "Hello, " + this.subject;
    };
    return Greeter;
}());

Однако, как правило, он работает таким же образом, когда он представленв качестве функции конструктора.Что, конечно, выглядит более JavaScriptish и написано от руки:)

function Greeter(subject) {
    this.subject = subject;
}
Greeter.what = function () {
    return "Greater";
};
Greeter.prototype.greet = function () {
    return "Hello, " + this.subject;
};

Использование:

Оба блока кода работают одинаково:

Greater.what();  // -> "Greater"
var greater = new Greater("World!");
greater.greet(); // -> "Hello, World!

Что такоепольза или мотивы, чтобы упаковать его в IIFE?

Я сделал наивный тест:

console.time("Greeter");
for(let i = 0; i < 100000000; i++) {
    new Greeter("world" + i);
}
console.timeEnd("Greeter");

Он показал практически одинаковую скорость реализации.Конечно, мы не можем ожидать никакой разницы, потому что IIFE разрешается только один раз.

Я думал, что, возможно, это из-за закрытия, но IIFE не принимает аргументов.Это не должно быть закрытием.

Ответы [ 2 ]

12 голосов
/ 11 мая 2019

TypeScript будет передавать аргументы IIFE в тех случаях, когда существует наследование между классами.Например, закрытие ниже используется, когда Greeter расширяет класс BaseGreeter:

var Greeter = /** @class */ (function (_super) {
    // __extends is added by the TS transpiler to simulate inheritance
    __extends(Greeter, _super);
    function Greeter(subject) {
        var _this = _super.call(this) || this;
        _this.subject = subject;
        return _this;
    }
    Greeter.What = function () {
        return "Greater";
    };
    Greeter.prototype.greet = function () {
        return "Hello, " + this.subject;
    };
    return Greeter;
}(BaseGreeter));
11 голосов
/ 11 мая 2019

Это сделано для сохранения поведения нативного класса в подобных случаях, когда кто-то пытается использовать класс Greeter до его определения:

// this is javascript code, not TypeScript

console.log(Greeter.What());

class Greeter {
}

Greeter.What = function What() {
    return "Greater";
}

При реализации нативного класса это должно вывести ReferenceError: Greeter is not defined.

При транспортировке и упаковке в IIFE результат достаточно близок: TypeError: Cannot read property 'What' of undefined.

Без IIFE развернутая функция имеет вид hoisted и имя Greeter находится в области видимостиперед его определением возникает другая ошибка: TypeError: Greeter.What is not a function

Обратите внимание, что IIFE не используется для сокрытия закрытых свойств экземпляра или класса, поскольку в любом случае это не нужно.При передаче свойства экземпляра назначаются как свойства для this внутри конструктора, а статические свойства назначаются как свойства объекта Greeter - переменные не создаются.

...