首页 > 解决方案 > 属性初始化顺序打字稿

问题描述

我在 Typescript 中有 2 个课程,A 和 B。B 派生自 A,A 的构造函数调用函数init,B 覆盖init。a.ts

export default class A {
    constructor() {
        this.init();
    }

    init() {
        console.log("A.init()")
    }
}

b.ts

import A from "./a"

export default class B extends A {
    public bx = 3;
    public by = 10;
    public bz = 0;
    constructor() {
        super();
    }

    init(){
        this.bx = 5;
        this.bz = this.by;
        console.log("B.init()")
    }
}

编译的js文件tsc就像

一个.js

export default class A {
    constructor() {
        this.init();
    }
    init() {
        console.log("A.init()");
    }
}

b.js

import A from "./a";
export default class B extends A {
    constructor() {
        super();
        this.bx = 3;
        this.by = 10;
        this.bz = 0; //even worse
    }
    init() {
        this.bx = 5;
        this.bz = this.by;
        console.log("B.init()");
    }
}

毫无意外a.js。但是在 中b.js,我们可以在构造函数的this.bx = 3;后面看到一行。super()虽然我同意有必要初始化一个像类this.bx = 3;中的声明这样的属性,但我根本无法理解为什么在这种情况下,它甚至this.bx=3;super()理论上编译器应该能够知道this.bx已经设置并且不是从 AST 未初始化. 有什么考虑如果该属性从未被分配,它应该只初始化一个属性。就我而言,我想应该是

import A from "./a";
export default class B extends A {
    constructor() {
        super();
    }
    init() {
        this.bx = 3; // initialisation from the declaration can appear here before the first time use. It can be optimized because of the next line assignment
        this.bx = 5; // first time use `this.bx`
        this.by = 10; // the initialisation here is because this.by is used in the next line
        this.bz = this.by; 
        console.log("B.init()");
    }
}

与 c# 比较

using System;
                    
public class Program
{
    public static void Main()
    {
        B b = new B();
        Console.Out.Write("x: " + b.x + " y: " + b.y);
    }
}

class A {
    public A() {
        init();
    }
    
    public virtual void init() {
    }
}

class B : A {
    public int x = 3;
    public int y = 10;
    public int z = 4;
    public B() : base() {
    }
    
    public override void init() {
        this.x = 5;
        this.y = this.z;
    }
}

你会得到x: 5 y: 4.

标签: typescript

解决方案


有充分的理由确保在扩展子类的初始化发生之前完全初始化您的基类,这是 MDN 文档中规定的super

在构造函数中使用时,super 关键字单独出现,并且必须在使用 this 关键字之前使用

通过让您的基类在其构造函数中调用一个覆盖this子类的属性的方法,您已经搞乱了初始化的顺序。由于违反了这一重要要求,编译器在此要求背后所做的任何假设现在都被打破了。

混乱随之而来……

这里最可取的结果是一个胖编译错误。


推荐阅读