TypeScript 中的私有属性

我们知道,TypeScript 是无法直接运行在浏览器中的,也无法直接运行在 nodejs 中。必须先编译成 js 以后才能运行在这些环境中。

当然这也不是绝对的,去年 nodejs 之父又新开了个坑——deno,能够直接运行 TypeScript。

之前因为觉得反正 TypeScript 最终是会编译成 js 运行在浏览器中或者 nodejs 环境中,那么是否 TypeScript 中所有的特性,都能在 js 中找到对应的书写方式呢?

之前看一些 TypeScript 中类型的实现,感觉蛮有意思的,特别是对比 TypeScript 源码和编译后的 js 代码:

比如 typeScript 中的枚举:

enum Color {
    Red = 1,
    Green,
    Blue
}
let c: Color = Color.Green;

编译以后的 js 代码:

var Color;
(function (Color) {
    Color[Color["Red"] = 1] = "Red";
    Color[Color["Green"] = 2] = "Green";
    Color[Color["Blue"] = 3] = "Blue";
})(Color || (Color = {}));
var c = Color.Green;

比如以前从没觉得,原来 js 可以这么玩,创建一个对象,对象里面的 key、value 可以互相映射,通过 key 可以找到 value,通过 value 也可以找到 key。当然这里面,你得把 key、value 理解成一类数据的代称,比如例子中得颜色和数值。

而且,从这个编译以后得 js 代码中,我学到了一个很有意思的技巧,原来对于对象的属性进行赋值的时候,执行完赋值语句以后,是有返回值的。

不过结合对象的 get\set 属性想想,就应该知道这个道理并不难理解了。

赋值,同样是调用了一个方法,最后给个返回值,这个返回值刚好是就是传入的值,以显示赋值成功,这个设计理念很好理解,也很符合逻辑。

当这个概念用久了,我就想当然的以为,TypeScript 中的代码应该所有的都能编译成对应的 JavaScript 代码,并且也应该是符合逻辑的。

但是直到我碰见了类中的私有属性,才颠覆了我这个惯性认知。

我们知道的是,Javascript 的类中是没有私有属性的,如果想模拟私有属性的话,必须要用闭包来模拟。

比如下面这段 TypeScript 代码

class Animal {
    private name: string;
    constructor(theName: string) {
        this.name = theName;
    }
    private sayName(): string {
        return this.name;
    }
}

我本以为编译成 JavaScript 会是这样的:

var Animal = /** @class */ (function () {
    var name;
    function Animal(theName) {
        name = theName;
    }
    Animal.prototype.sayName = function () {
        return name;
    };
    return Animal;
}());

如果编译以后,代码是像我预料的这样的话,那么这个地方的私有属性也就合情合理了,毕竟我在这个类的外部是完全无法访问到这个属性的,只在定义这个类的作用域内部才能访问到。

但是实际上,我用最新的 TypeScript 3.1 版本编译上述代码以后,结果是这样的:

var Animal = /** @class */ (function () {
    function Animal(theName) {
        this.name = theName;
    }
    Animal.prototype.sayName = function () {
        return this.name;
    };
    return Animal;
}());

这个结果刚开始让我很难理解,这样定义构造函数,这个 name 怎么能算上是私有属性呢?

这个问题我纠结了很久,苦思不得其解。

知道我看到了 deno,我才想明白,其中的缘由。

我们知道,TypeScript 是 JavaScript 的超集,那么就说明,TypeScript 中的概念不一定在 JavaScript 中存在,但是反过来是肯定的。

明白了这一点,就不难理解其缘由了。

TypeScript 解决了 JavaScript 中的一些痛点,没有类型约束、浏览器支持滞后等等。但是这不意味着,TypeScript 就等同于 JavaScript 了。如果两者完全等同,何必要花费这么大力气造一个新的轮子呢?

TypeScript 编译成 JavaScript 后的代码,如果你混合着别的 JavaScript 源码来用,照样是缺乏安全性保障的。但是它安全性体现在,我们如果全部是用 TypeScript 来写我们的项目,编译器会负责把我们 TypeScript 源码编译成能正确运行的 JavaScript 代码,并且至少有 99.99% 的概率能够确保在运行期间不会出错。

这不由得让我联想到,机器码和高级编程语言之间的关系。既然所有的编程语言都需要编译成机器码才能跑在计算机上,那么为什么我们说 JavaScript 写的代码安全性太差,而 Java 写出来的代码安全性更好,更适用于大型的工程呢?

究其原因,大概就是因为,不同语言对使用者的要求是不尽相同的吧。深谙 JavaScript 的老手,写出来的代码,我不相信会比一个 Java 新手写出来的代码可靠性要差。

如果把 JavaScript 比作是一把砍刀,那么 Java 就是一把匕首。

砍刀看起来威风八面,作战半径很大,只要是个力气大的人,拿起来就敢上战场砍人。但是匕首呢,很多人拿着就很发怵了,这玩意这么短,拿着砍人不是送人头么。

砍刀虽好用,但是想用好却难,用来有效的杀敌更难;匕首虽然难习,但是一旦习成,近战肉搏,杀人效率堪称恐怖如斯。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
TypeScript,模板类是指一种可以在其他类复用的类。它可以通过泛型来实现参数化类型。 模板类的定义方式与普通类相似,只需要在类名后面添加<T>,其T是一个类型参数,可以在类属性和方法使用。 例如,我们可以创建一个模板类`GenericClass`: ```typescript class GenericClass<T> { private value: T; constructor(value: T) { this.value = value; } public getValue(): T { return this.value; } public setValue(value: T): void { this.value = value; } } ``` 在这个例子,模板类`GenericClass`有一个泛型类型参数T,通过这个泛型类型参数可以在类属性和方法使用。在构造函数,我们可以传入任意类型的值,并将其存储在私有属性`value`。通过`getValue`方法可以获取存储的值,通过`setValue`方法可以修改存储的值。 使用模板类时,我们可以指定具体的类型参数,比如: ```typescript const numberClass = new GenericClass<number>(10); console.log(numberClass.getValue()); // 输出: 10 const stringClass = new GenericClass<string>('Hello'); console.log(stringClass.getValue()); // 输出: Hello ``` 在上面的代码,我们分别创建了一个`numberClass`和一个`stringClass`实例,分别传入了一个数字和一个字符串作为构造函数的参数。通过调用`getValue`方法,我们可以获取存储的值。 总结一下,在TypeScript,模板类是一种可以通过泛型来实现参数化类型的类。通过使用模板类,我们可以在其他类复用代码,提高代码的可复用性和灵活性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值