Ami*_*ner 3 javascript oop es6-class
我需要在 JavaScript 中扩展一个单例类。
我面临的问题是我获取了我所扩展的类实例,而不是仅获取了该类的方法。
我尝试删除super以获取实例,但随后出现错误
在访问“this”或从派生构造函数返回之前,必须调用派生类中的超级构造函数
代码示例:
let instanceA = null;
let instanceB = null;
class A {
constructor(options) {
if (instanceA === null) {
this.options = options;
instanceA = this;
}
return instanceA;
}
}
class B extends A {
constructor(options) {
if (instanceB === null) {
super()
console.log('real class is ' + this.constructor.name)
this.options = options
instanceB = this;
}
return instanceB;
}
}
const a = new A({
i_am_a: "aaaaaa"
});
const b = new B({
i_am_b: "bbbbbb"
}) // this change a
console.log(b.options)
console.log(a.options)Run Code Online (Sandbox Code Playgroud)
所以,首先这里有一个误解:
我尝试删除 super 以不获取实例,但随后出现错误
super()在创建的子类实例上调用父类的构造函数this(即引用的内容)。它不返回父类实例。浏览此处获取更多信息。
所以,调用super()根本不违反父类的单例属性。如果正确实施,它很可能只会构建一次。
考虑到这一点,您应该稍微改进您的代码。
一个明智的改变是从构造函数中删除实例管理。一种解决方案是使用静态构造函数,它要么在不存在实例的情况下创建单例,要么返回创建的实例。
另一种方法是删除单例类构造函数的参数。将参数传递给一个应该实例化一次的类并没有真正的意义(你永远不会再对构造函数参数做任何事情)。您可以立即设置单例的参数属性。这是支持 Java 单例这一点的SO 答案。
具有静态构造函数且不带参数的完整示例如下所示:
let instanceA = null;
let instanceB = null;
let counters = { A: 0, B: 0 }; // count class instantiations
class A {
static getInstance() {
if (instanceA === null) {
instanceA = new A();
}
return instanceA;
}
whoami() {
const name = this.constructor.name;
return `${name} #${counters[name]}`;
}
constructor() {
counters[this.constructor.name] += 1;
}
}
class B extends A {
static getInstance() {
if (instanceB === null) {
instanceB = new B();
}
return instanceB;
}
constructor() {
super();
}
}
const a1 = A.getInstance();
const a2 = A.getInstance();
const a3 = A.getInstance();
const b1 = B.getInstance();
const b2 = B.getInstance();
const b3 = B.getInstance();
console.log(a1.whoami());
console.log(a2.whoami());
console.log(a3.whoami());
console.log(b1.whoami());
console.log(b2.whoami());
console.log(b3.whoami());Run Code Online (Sandbox Code Playgroud)
请注意,B继承whoami自A且构造函数调用计数器永远不会增加到超过 1。
显然,使用这种方法,您不能保证单例属性适用于每个类,除非仅使用静态构造函数来生成实例(因为构造函数仍然可以访问)。我认为这是一个很好的妥协。