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.xthis.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();
    }
}

它的输出是 233,为什么?

this.x2 好理解,super.x3 也好理解。而 getValue() 中实际取的是父类中的 x,似乎有点不好理解——

其实也不难理解,因为子类中重新定义了 x,它和父类中的 x 就不是同一个东西了,只是正好名称相同而已。

另一个方面来理解:子类中重新定义 x,而不是重载(也不可能重载字段,只有方法和属性可以重载),那么 getValue() 就不会顺着虚函数链去找到最近的一个定义,也就不会取到子类中的赋值。

TypeScript

在 TypeScript 的 Playground 中运行下面的代码确实可以得到 232

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 的两个条件,一个是 publicprotected 修饰,二个是 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 的结果 3undefined3

……

可是,我除了说不能理解之外,还能说什么呢?

既然 super.x = 3 都可以起作用,凭什么 console.log(super.x) 就取不到值?从这一点上来说,Babel 的结果 (2undefined2) 反而更符合逻辑。

小结

ES6 的结果我不能理解,也许能从 ECMAScript 2015 Language Specification 中找到答案,不过我没耐心去阅读这个长而枯燥的英文文档——如果有人找到了答案,麻烦告诉我一声,万分感谢!

不管怎么说,我用 TypeScript 的时间比较多,而且忠实于编译器的错误提示。因此在我实际工作中遇到类似问题的概率非常低,不纠结 ^_^


边城客栈
全栈技术专栏,公众号「边城客栈」,[链接]

一路从后端走来,终于走在了前端!

57.4k 声望
27.6k 粉丝
0 条评论
推荐阅读
树,计算父节点的值
前段时间回答了一个类似的问题,产生了写一篇博客的想法。这个问题确实存在一些常见的的应用场景,比如一个多层组织结构中,已知每个员工的绩效分,希望计算各级部门的绩效分以便对部门评优。

边城7阅读 441评论 2

封面图
正则表达式实例
收集在业务中经常使用的正则表达式实例,方便以后进行查找,减少工作量。常用正则表达式实例1. 校验基本日期格式 {代码...} {代码...} 2. 校验密码强度密码的强度必须是包含大小写字母和数字的组合,不能使用特殊...

寒青57阅读 8.5k评论 11

JavaScript有用的代码片段和trick
平时工作过程中可以用到的实用代码集棉。判断对象否为空 {代码...} 浮点数取整 {代码...} 注意:前三种方法只适用于32个位整数,对于负数的处理上和Math.floor是不同的。 {代码...} 生成6位数字验证码 {代码...} ...

jenemy49阅读 7.2k评论 12

再也不学AJAX了!(二)使用AJAX ① XMLHttpRequest
「再也不学 AJAX 了」是一个以 AJAX 为主题的系列文章,希望读者通过阅读本系列文章,能够对 AJAX 技术有更加深入的认识和理解,从此能够再也不用专门学习 AJAX。本篇文章为该系列的第二篇,最近更新于 2023 年 1...

libinfs42阅读 6.9k评论 12

封面图
「多图预警」完美实现一个@功能
一天产品大大向 boss 汇报完研发成果和产品业绩产出,若有所思的走出来,劲直向我走过来,嘴角微微上扬。产品大大:boss 对我们的研发成果挺满意的,balabala...(内心 OS:不听,讲重点)产品大大:咱们的客服 I...

wuwhs32阅读 3.5k评论 5

封面图
安全地在前后端之间传输数据 - 「3」真的安全吗?
在「2」注册和登录示例中,我们通过非对称加密算法实现了浏览器和 Web 服务器之间的安全传输。看起来一切都很美好,但是危险就在哪里,有些人发现了,有些人嗅到了,更多人却浑然不知。就像是给门上了把好锁,还...

边城29阅读 6.4k评论 5

封面图
2022大前端总结和2023就业分析
我在年前给掘金平台分享了《2022年热点技术盘点》的前端热点,算是系统性的梳理了一下我自己对前端一整年的总结。年后,在知乎上看到《前端的就业行情怎么样?》,下面都是各种唱衰前端的论调,什么裁员,外包化...

i5ting27阅读 2.3k评论 4

封面图

一路从后端走来,终于走在了前端!

57.4k 声望
27.6k 粉丝
宣传栏