【问题标题】:Why private variable in a class is treated as public in the transpiled code为什么类中的私有变量在转译代码中被视为公共变量
【发布时间】:2017-09-24 15:19:50
【问题描述】:

我在打字稿中添加了以下类

class Person {
    private variable1;
    public varibele2;

    Person(){
        this.variable1 = 'abc';
        this.varibele2 = 'xyz'; 
    }

    public getVariable1(){
        return this.variable1;        
    }
}

所以当我使用 tsc 编译代码时,它会生成以下代码

var Person =  (function () {
    function Person() {
    }
    Person.prototype.Person = function () {
        this.variable1 = 'abc';
        this.varibele2 = 'xyz';
    };
    Person.prototype.getVariable1 = function () {
        return this.variable1;
    };
    return Person;
}());

由于 variable1 是私有的,该类的 obj 不应访问(这发生在 typescript 代码中)。

转译后的 es5 代码应该会发生相同的行为(但不会发生)。

在上面示例的转译代码中,我正在创建 Person 的对象

var p = new Person();
console.log(p.variable1); // undefined 
p.variable1 = 'abc1';  // setting value to variable 1 
console.log(p.variable1); // 'abc1'
console.log(p.getVariable1()); // 'abc1'

在上面的代码中,我应该无法设置或获取 variable1 的值。

var p = new Person();
console.log(p.getVariable1()); // 'undefined' 
p.variable1 = 'abc1';  // setting value to variable1 
console.log(p.getVariable1()); // 'abc1'

在上面的代码中,我尝试使用 p.getVariable1() 获取值,但我得到了 undefined。由于值已经在类的构造函数中分配,它应该可以通过 p.getVariable1() 获得

var p = new Person();
console.log(p.variable2); // undefined
p.variable2 = 'xyz1'; // setting value
console.log(p.variable2);// 'xyz1'

在上面的代码中,Variable2 应该返回 'xyz' 但它不是。一旦我给它赋值,它就会返回。

因此,私有变量和公共变量的行为在转译代码中是相同的,并且非常令人困惑。 它不返回在构造函数中分配的值。

【问题讨论】:

  • Javascript 没有私有变量。 Typescript 的私有变量只在编译时检查,这对开发很有用,但在运行时不提供保护。
  • 我知道 javascript 不提供访问修饰符(保护或数据隐藏)的概念,但是有一种方法可以使用闭包实现数据隐藏,但是这里编译的代码没有实现适当的闭包以使变量公开和私人的。
  • 是的,闭包可以使变量私有化,但这不是 typescript 的目标。 Typescript 提供编译时检查,仅此而已。
  • 是否有理由需要在运行时进行检查?当您尝试访问p.variable1 时,IDE 或构建过程告诉您存在类型错误还不够吗?
  • 我在想浏览器理解什么,它理解编译后的 javascript,如果编译后的 javascript 不遵循相同的概念,那么在编译时将变量设为私有和公共有什么用。

标签: javascript typescript ecmascript-5 typescript2.0 tsc


【解决方案1】:

为了继续我们与 cmets 的讨论,以下是使用公共与私有的好处:

IDE 会立即告诉您您正在做一些您不应该做的事情。如果您忽略这些错误,代码将编译为 javascript 并运行,但关键是您不要忽略这些错误。当你写出这样糟糕的代码时,打字稿会告诉你有问题,然后你就可以解决问题。如果您有构建过程,您可以对其进行设置,以便这些打字稿错误将导致构建失败,从而迫使您在部署之前解决问题。

Typescript 是一种工具,可帮助您更早、更轻松地捕获错误,从而帮助您编写更好的 javascript 代码。它不是改变 javascript 工作方式的工具。 Typescript 不提供运行时类型检查,如果这是您所追求的,您将找不到它。如果您需要闭包来隐藏变量,请自己创建一个闭包。

【讨论】:

  • 我的问题仍然是“如果运行时一切都是公共的,为什么打字稿中的公共和私人变量的概念?”。为什么打字稿中不能只有默认的公共概念?
  • 更早、更轻松地发现错误。
  • 你能解释一下我们如何通过将变量设为私有和公共来捕获错误吗?
  • 在我刚刚发布的截图中,红色下划线指出了两个错误。
  • 你没有理解我的问题。如果我没有访问修饰符的概念,我不能抓住错误吗?你说的是特定于IDE。好的,告诉我访问修饰符 i general 的用途是什么?
【解决方案2】:

首先,回答您的主要问题:

为什么类中的私有变量在转译代码中被视为公共变量。

private 属性以及readonly 属性确实被转换为普通属性,因此是“公共的”。我认为这是为了简化和促进转译 TS→JS 并支持在任何地方使用 TypeScript,在这些属性上执行无效操作时会发出警告或错误:访问类外的私有属性,重新分配只读属性...

但是你举了一些非常奇怪的例子。它们不是由于 TypeScript 转译造成的。我注意到您的班级 Person 的一些问题导致了他们:

  • 在 ES6 和 TypeScript 中,类构造函数是使用关键字 constructor 定义的,而不是类名。更令人困惑的是,构造函数被转译成一个函数构造函数,名称与类类似,此处为Person
  • 第二个属性有错字:varibele2 而不是variable2。这就是console.log(p.variable2) 无法打印预期值的原因。

解决了这些问题,代码的行为更加合乎逻辑。

class Person {
    constructor(private _variable1 = 'abc', public variable2 = 'xyz') { }

    public get variable1() { return this._variable1; }
}

console.log(new Person()); // → Person { v1: [Getter], v2: "xyz", _v1: "abc", __proto__... }

转译后的代码可通过TypeScript playground 获得。

注意:我喜欢另一种语法:

  • 属性直接在构造函数中声明:它更紧凑,支持类型推断,我们可以指定其他初始值。
  • 私有变量被命名为_x,以便于编写getter get x() { return this._x; }。这也是一种常用的 JavaScript 约定,表示该变量是私有的,没有复杂的模式来真正拥有私有属性。

【讨论】:

    【解决方案3】:

    如果转译后的代码没有使用闭包将其设为私有,这意味着我可以在将其用作 javascript 库时忽略变量,因为我永远不会知道什么是私有的,什么不是。所以答案是转换 typescript 的方式是不正确的,并且不符合 javascript 的使用精神。

    【讨论】:

    • 不使用闭包函数将 typescript 私有转换为转译的 Js 意味着另一个 js 中的某些方法可以在不需要的情况下更改我们变量的值。
    【解决方案4】:

    根据我的理解,在以下情况下,变量 2 未定义,因为对象 p 不包含该变量。

    在下面的代码中,我们使用 p.variable2 = 'xyz1' 将变量包含到对象 p 中。所以在第三行我们得到了那个变量的值。

    var p = new Person();
    console.log(p.variable2); // undefined
    p.variable2 = 'xyz1'; // setting value
    console.log(p.variable2);// 'xyz1'
    

    问题仍然是既然 typescript 已经声明了变量,那么为什么 javascript(编译代码)对象不包含这些变量?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-08-21
      • 2011-05-25
      • 1970-01-01
      • 2017-04-10
      • 2011-12-03
      • 2015-07-17
      • 2012-10-04
      相关资源
      最近更新 更多