创建只有抽象 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);
好的,我有一个奇怪的给你们。所以我们有:
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);