内容简介:ES6 / TypeScript / Babel / C# 中的 super(base)
今天看到@justjavac 写的《 ES6 中的 this & super:babel 和 typescript 都错了 》,觉得很有意思,所以也研究了一下。
借用@justjavac 的示例代码,略做修改,然后在几种语言中跑了一下,结果
语言(版本) | 输出1 | 输出2 | 输出3 |
---|---|---|---|
ES6 | 3 | undefined | 3 |
Babel | 2 | undefined | 2 |
TypeScript (?) | 2 | 3 | 2 |
C# | 3 | 3 | 3 |
Java | 3 | 3 | 3 |
是的,我加入了 C# 和 Java 的运行结果,毕竟它们是真正的 OOP 语言。另外请注意到,我在 TypeScript 后面加了个问号 (?)
,因为实际上 TypeScript 虽然编译成了对应的 JS,但是转译过程中是会报错的:
index.ts (20,15): Only public and protected methods of the base class are accessible via the 'super' keyword. (2340) index.ts (22,27): Only public and protected methods of the base class are accessible via the 'super' keyword. (2340)
下面,我从 C#/Java 说起
C# / Java
对于 C#/Java 这样的真正的 OOP 语言来说, super.x
和 this.x
其实是一个东西,因为在子类中没有重新定义这个成员 x
。以 C# 代码为例
using System; public class Program { public static void Main() { var t = new ColorPoint(); t.test(); } } class Point { public int x; protected void getValue() { Console.WriteLine(this.x); } } class ColorPoint : Point { public ColorPoint() { this.x = 2; base.x = 3; Console.WriteLine(this.x); Console.WriteLine(base.x); } public void test() { this.getValue(); } }
上面这段代码是为了与下面这段代码进行比较——假如我们在子类中重新定义 x
呢?
class ColorPoint : Point { public new int x; public ColorPoint() { this.x = 2; base.x = 3; Console.WriteLine(this.x); Console.WriteLine(base.x); } public void test() { this.getValue(); } }
它的输出是 2
、 3
、 3
,为什么?
this.x
是 2
好理解, super.x
是 3
也好理解。而 getValue()
中实际取的是父类中的 x
,似乎有点不好理解——
其实也不难理解,因为子类中重新定义了 x
,它和中的 x
就不是同一个东西了,只是正好名称相同而已。
另一个方面来理解:子类中重新定义 x
,而不是重载(也不可能重载字段,只有方法和属性可以重载),那么 getValue()
就不会顺着虚函数链去找到最近的一个定义,也就不会取到子类中的赋值。
TypeScript
在 TypeScript 的 Playground
中运行下面的代码确实可以得到 2
、 3
、 2
:
class Point { public x: number; protected getValue() { console.log(this.x); } } class ColorPoint extends Point { constructor() { super(); this.x = 2; super.x = 3; console.log(this.x); console.log(super.x); } test() { this.getValue(); } } const t = new ColorPoint(); t.test();
问题在于,不管是在 Playground 还是 VSCode 还是 vsc(编译器),都会得到错误提示
Only public and protected methods of the base class are accessible via the 'super' keyword.
这里提到了用 super
的两个条件,一个是 public
或 protected
修饰,二个是 methods
。第二个条件就是关键所在:TypeScript 中只能通过 super
调用方法,所以 super.x
从语法上来说就是错的!我不知道 Anders Hejlsberg 为什么要在语法错误的情况仍然输出结果——也许是为了容错性。但既然用 TypeScript,就是为了用它的静态检查,所以要充值关注编译错误提示。
现在来试验一下介于 field 和 method 之间的情况,使用 getter/setter 语法的属性。
class Point { private _x: number; public get x(): number { return this._x; } public set x(value: number) { this._x = value; } protected getValue() { console.log(this.x); } }
很遗憾,同样的错误。就这一点来说,我觉得 TypeScript 还有待进步。
ES6 / ES2015 / Babel
ES6 的正式名称是 ECMAScrip 2015,即 ES2015
那么,现在来说说 ES6 的结果 3
、 undefined
、 3
。
……
可是,我除了说不能理解之外,还能说什么呢?
既然 super.x = 3
都可以起作用,凭什么 console.log(super.x)
就取不到值?从这一点上来说,Babel 的结果 ( 2
、 undefined
、 2
) 反而更符合逻辑。
小结
ES6 的结果我不能理解,也许能从 ECMAScript 2015 Language Specification 中找到答案,不过我没耐心去阅读这个长而枯燥的英文文档——如果有人找到了答案,麻烦告诉我一声,万分感谢!
不管怎么说,我用 TypeScript 的时间比较多,而且忠实于编译器的错误提示。因此在我实际工作中遇到类似问题的概率非常低,不纠结 ^_^
!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。