创建只有抽象 class 可以在 JavaScript 中访问的静态方法

Creating static methods that only the abstract class can access in JavaScript

好的,我有一个奇怪的给你们。所以我们有:

class Animal {
    static PublicMethod() {
        console.log('I am abstract!');

        this.OnlyForAnimal(); // Good, Animal is allowed!
    }
}

class Dog extends Animal {
    static OnlyForAnimal() { // Currently accessible by anyone.
        console.log('Only the Animal class should be able to use this function...');
    }
}


Dog.OnlyForAnimal(); // No, no one should be allowed to do this!

那么,是否可以使静态方法只能由抽象 class 使用,或者如果抽象 class 以外的其他人调用该方法则抛出错误?我们可以在 Dog class 中输出摘要的名称或对象吗 class?

从你的问题来看,你似乎想在 Dog 中声明一个只有 Animal 可以使用的静态方法。

如果不以某种方式 Animal 进行设置,您将无法做到这一点。您有几个选择:

  • 通过 Symbol 或
  • 略显晦涩
  • 隐私权来自 WeakMap

(很容易想到我们可以将其中一个新的私有 class 特性应用到此(fields, or static private methods,等等),但这样做可能只会更多比 WeakMap 复杂,但没有真正提供任何东西,而且你必须在注册时创建 Dog 的子 class。所以我在这里没有这样做。)

有点模糊

如果稍微模糊而不是实际隐私就足够了,你可以Animal创建一个符号并使用Dog添加一个方法Symbol:

const Animal = (() => {
    const hidden = Symbol.for("Animal_hidden_static_method");
    // Or: `const hidden = Symbol();` if you don't need to worry about
    // cross-window issues

    return class Animal {
        static PublicFunction() {
            console.log('I am abstract!');
        }

        static registerClass(cls) {
            cls[hidden] = function() {
                // `Animal` can easily call this method; others have
                // to work harder to do do it
            };
        }

        static useTheMethod(cls) {
            cls[hidden](); // <== Calls the method with `this` set to the class constructor
        }
    };
})();

class Dog extends Animal {
}
Animal.registerClass(Dog);

// ...
Animal.useTheMethod(Dog);

不过,这只是轻微的模糊,不是隐私。任何东西都可以在 Dog 上使用 Object.getOwnPropertySymbols 来查找命名该方法的符号。

实际隐私

如果您需要真正的隐私,您可以完全不将方法放在 Dog 上,而是通过 WeakMap 创建一个与 Dog 相关联的函数来做到这一点Animal 有权访问:

const Animal = (() => {
    const methods = new WeakMap();

    return class Animal {
        static PublicFunction() {
            console.log('I am abstract!');
        }

        static registerClass(cls) {
            methods.set(cls, function() {
                // Only `Animal` can call this function. The function is garbage-collectable
                // when the class used as a the key is garbage-collectable
            });
        }

        static useTheMethod(cls) {
            const method = methods.get(cls);
            method.call(cls); // <== Calls the method with `this` set to the class constructor
        }
    };
})();

class Dog extends Animal {
}
Animal.registerClass(Dog);