使用TypeScript编译类的观察

时间:2013-12-30 11:33:20

标签: javascript class compiler-construction typescript access-modifiers

在我继续之前,我想指出我已经提出了几个关于TypeScript,它的编译器以及它有什么问题的问题,并且在整个生命周期和版本1.0的路线图中都没有实现

此问题涉及在TypeScript中使用publicprivate个关键字,以及这些关键字与已编译的JavaScript的关系。

考虑以下TypeScript类:

class Example {
    private messageA: string;
    public messageB: string;

    constructor(message?: string) {
        this.messageA = "private: " + message;
        this.messageB = "public: " + message;
    }

    public showMessageA(): void {
        alert(this.messageA);
    }

    private showMessageB(): void {
        alert(this.messageB);
    }
}

var example = new Example("Hello World");

现在,当我输入example时。 intellisense( TypeScript )告诉我,我可以访问messageBshowMessageA,因为它们都是public。但是,这种行为(虽然可能)在编译的JavaScript中并不明显。

以下是我班级的JavaScript编译:

var Example = (function () {
    function Example(message) {
        this.messageA = "private: " + message;
        this.messageB = "public: " + message;
    }
    Example.prototype.showMessageA = function () {
        alert(this.messageA);
    };

    Example.prototype.showMessageB = function () {
        alert(this.messageB);
    };
    return Example;
})();

var example = new Example("Hello World");

现在,如果我将此示例粘贴到我的浏览器控制台(我正在使用Chrome),我可以访问messageAmessageBshowMessageAshowMessageB在JavaScript中,忽略所有访问修饰符。

就个人而言,我认为这是错误的! JavaScript能够建模访问修饰符,因此我相信TypeScript应该效仿。

请考虑以下手工编写的JavaScript,它可以正确地为privatepublic变量和函数建模:

var Example = (function() {
    return function Example(message) {
        var messageA = "private: " + message;
        this.messageB = "public: " + message;

        this.showMessageA = function() {
            alert(messageA);
        }

        var showMessageB = function() {
            alert(this.messageB);
        }
    }
})();

var example = new Example("Hello World");

现在,如果我将此示例粘贴到我的浏览器控制台中,我只能访问messageBshowMessageA,这与我尝试使用TypeScript实现的目标是正确的。

问题

  1. 为什么TypeScript编译器在编译为JavaScript时会忽略访问修饰符?
  2. 为什么TypeScript会将所有方法绑定到原型,而不是基于每个实例?
  3. 如果与我的自定义实现相比,TypeScript编译类的方式有什么好处,它是什么,为什么?

2 个答案:

答案 0 :(得分:4)

使用闭包来模仿私有访问的问题是每个实例都需要自己的每个方法的副本。这意味着每次创建实例时,都必须编译每个方法函数,并且必须为新函数保留内存空间。这并不理想,也不是TypeScript想要实现的目标。

答案 1 :(得分:3)

从语义上讲,您描述的方法 - 闭包模型在很多方面优于JavaScript在原型上放置方法的模型 - 即使对于公共方法也是如此。 EcmaScript 6委员会中的一些人(TypeScript所基于的类系统)会喜欢沿着这些方向的类系统。实际上,TypeScript的早期内部版本实现了这样的模型。

不幸的是,这样的模型在JavaScript中无法有效。它通常要求每个方法都被分配为每个对象实例的单独闭包 - 即,创建单个对象实例将涉及创建许多函数对象。由于JavaScript对this及其功能识别概念的处理方式令人难过,因此没有简单的方法可以对这些分配进行优化。

因此,EcmaScript 6确定了当前模型(虽然它现在只公开),并且遗憾地遵循TypeScript(公共和私有)。然后,私有成员只在TypeScript中提供静态检查,没有封装保证。

FWIW,在这个模型中提供私有化的正确方法是私有符号(又名private names),但不幸的是,那些没有进入ES6,并且无论如何都不是TypeScript的选项。