ES6 / TypeScript / Babel / C# 中的 super(base)

本日看到 @justjavac 写的《ES6 中的 this & super:babel 和 typescript 都错了》,以为很有意思,所以也研讨了一下。

借用 @justjavac 的示例代码,略做修正,然后在几种言语中跑了一下,效果

言语(版本)输出1输出2输出3
ES63undefined3
Babel2undefined2
TypeScript (?)232
C#333
Java333

是的,我加入了 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 的时间比较多,而且忠厚于编译器的毛病提醒。因此在我现实工作中碰到类似问题的几率异常低,不纠结 ^_^

    原文作者:边城
    原文地址: https://segmentfault.com/a/1190000009529572
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞