从父类调用重写的静态方法

Calling an overridden static method from parent

本文关键字:静态方法 重写 调用 父类      更新时间:2023-09-26

首先,一些设置舞台的代码:

var instances = [];
class Parent {
    static doImportantStuff() {
        console.log( 'Parent doing important stuff' );
        return false;
    }
    static init() {
        if ( this.doImportantStuff() )
            instances.push( new this() );
    }
}
class Child1 extends Parent {
    static doImportantStuff() {
        console.log( 'Child 1 doing important stuff' );
        if (someCondition) return true;
        return false;
    }
}
class Child2 extends Parent {
    static doImportantStuff() {
        console.log( 'Child 2 doing important stuff' );
        if (someOtherCondition) return true;
        return false;
    }
}

这个想法是,有一个类Parent,几个Child类扩展。Child类的初始化基本相同,但每个doImportantStuff()类都有自己的实现,其返回值表示是否应该实例化特定的Child

到目前为止,这在我尝试过的每个转译器中都有效,因为Parent.init()函数中的this引用了Child类的构造函数。然而,我还没有找到任何文档说一种方式或其他关于引用一个子类覆盖的静态方法,所以问题是,我可以依靠这总是这样吗?或者,有其他方法可以做到这一点吗?

然而,我还没有找到任何文档说一种方式或其他关于引用一个子类覆盖的静态方法,所以问题是,我可以依靠这总是如此吗?

这是标准的函数通过对象属性调用机制。当你这样做的时候:

Child1.doImportantStuff();

…除非doImportantStuff是一个箭头函数(它不是)或绑定函数(它不是),否则在调用期间,this被设置为Child1。就像:

var obj = {
   foo: function() {
        console.log(this === obj);
   }
};
obj.foo();   // "true"

所以,是的,你可以依靠它。(我理解你为什么要问,除非你仔细研究,否则看起来有点奇怪。)

当然,它不能在非static函数的代码中工作,因为this将引用实例,而不是构造函数。如果你需要它,你可以使用this.constructor.doImportantStuff,除非有人把constructor属性弄乱了。(过去人们总是把事情搞砸;随着新语法的自动化,希望这种情况会更少发生,尽管很少你真的需要它…)


对于这类问题,记住新的类语法几乎是只是我们以前冗长的处理方式的语法糖(如果我们真的很彻底的话)通常是有用的。这是一种非常好的糖,但这几乎就是它的全部(这是一件好事)。static方法设置为构造函数的属性,非static方法在构造函数的prototype属性上设置为对象的属性。(我认为唯一没有糖的方面是,正如Bergi指出的那样,新的语法让我们可以扩展像Array这样的内置代码,这在以前是不可能做到的。实现这一目标的部分原因与this如何以及何时设置有关[在子类构造函数中不能在调用super()之前访问它],这与new.target有关,Bergi在这里讨论了CC_22。在ES7中,它可能会在隐私方面更进一步。)

如果你不想调用

Child1.doImportantStuff();

,而是动态地调用被覆盖的静态方法,您可以这样做:

this.constructor.doImportantStuff();

这也适用于setter和父类的构造函数:

class Parent {
    static get foo() {
        // Throw an error to indicate that this is an abstract method.
        throw new TypeError('This method should be overridden by inheriting classes.');
    }
    constructor() {
        console.log(this.constructor.foo);
    }
    logFoo() {
        console.log(this.constructor.foo);
    }
}
class Child extends Parent {
    static get foo() {
        return 'yay';
    }
}
const child = new Child(); // Prints 'yay'
child.logFoo(); // Prints 'yay'