Javascript类:如何在父类代码中访问重写的父类函数

时间:2017-10-04 16:45:17

标签: javascript class inheritance ecmascript-6 method-overriding

Javascript ES6(节点8.4.0和最新的Chrome和最近的Firefox)

我期待

class Parent {
    init(){
        console.log("Parent init") ;
        this._surname = "McClass" ;
    }
    constructor() {
        console.log("Parent constructor") ;
        this.init();
    }

    get surname(){
        return this._surname ;
    }
}

class Child extends Parent {

    init(){
        console.log("Child init") ;
    }
    constructor() {
        super();
        console.log("Child constructor") ;
        this.init();
    }    
}

var child = new Child() ;

console.log(child.surname);

给出以下输出;

Parent constructor
Parent init
Child constructor
Child init
McClass

(这是可比的C ++代码给出的)

唉,我得到了这个;

Parent constructor
Child init
Child constructor
Child init
undefined

我做错了什么或这是正确的预期行为,如果是这样,它是如何合理的?

修改;

请参阅下面的MinusFour的答案,了解如何实现我的目标/期望。

至于为什么观察到的输出是"正确"行为和合理;

正如Bergi所指出的那样(在评论中)所有对js中对象方法的调用都是有效的"虚拟" (该名称的最后一个方法添加到对象的原型继承链中,是第一个找到并因此执行的方法)。事实证明,在类构造环境中调用仍然是有效的。

C ++在构造期间不应用虚拟方法行为,但Java会再次使用类似的Java代码获得相同的输出(如上所述),因此观察到的行为有先例。

2 个答案:

答案 0 :(得分:2)

你可以这样做:

Scanner sc = new Scanner(System.in);
System.out.println("\nEnter your color\n" + 
                       "BLUE, BLACK, ORANGE, WHITE, YELLOW, RED, GREEN, PINK:");

String str = sc.next();
str = str.toUpperCase();

private ArrayList<Color> colorArray= new ArrayList<Color>();

// Here I want to put the colors (string str) in the colorArray arraylist.

Parent.prototype.init.call(this);

要确保它永远不会被覆盖,但我建议你不要首先覆盖它。

答案 1 :(得分:0)

这是预期的行为,因为它可以在遵循规范的已建立的ES6类实现中看到。

this引用当前类实例,在实例化Child的情况下是Child的实例 - 即使在Parent类中,因为只有一个实例,它是instanceof Child

如果Child覆盖了该方法,则它有责任提供调用它的机制。考虑到init遵循一些记录的约定,并且是为了使构造函数更精简和更可测试而进行类初始化的地方,它是:

class Parent {
    init(){...}
    constructor() {
        this.init();
    }
    ...
}

...

class Child extends Parent {
    init(){
        super.init();
        ...
    }
    // optional, as long as `init` contains all init logic
    constructor() {
        super();
    }    
}

结果如下:

Parent constructor
Parent init
Child init
Child constructor

如果init应该在两个类中完全独立工作,则不应该覆盖它。方法的名称应不同,例如initParentinitChild。或者可以使用任何其他避免命名冲突的方法,例如:

const init = Symbol('Parent init');
class Parent {
    [init](){...}
    constructor() {
        this[init]();
    }
    ...
}

...

const init = Symbol('Child init');
class Child extends Parent {
    [init](){...}
    constructor() {
        this[init](); // totally independent method
    }
}