我在使用Singleton模式的javascript es6继承中发现了错误行为。
代码:
let instanceOne = null;
class One {
constructor() {
if (instanceOne) return instanceOne;
this.name = 'one';
instanceOne = this;
return instanceOne;
}
method() {
console.log('Method in one');
}
}
let instanceTwo = null;
class Two extends One {
constructor() {
super();
if (instanceTwo) return instanceTwo;
this.name = 'two';
instanceTwo = this;
return instanceTwo;
}
method() {
console.log('Method in two');
}
}
const objOne = new One();
const objTwo = new Two();
console.log(objOne.name);
console.log(objTwo.name);
objOne.method();
objTwo.method();
显示:
two
two
Method in one
Method in one
继承以某种方式搞砸了。这里的属性被覆盖,但不是对象方法。
我的问题是为什么它会起作用(比如现在抛出)并且你能解释一下这种行为吗?
看来新对象需要全新的对象作为父对象(请参阅下面的解决方案)。
如果您遇到同样的问题,这是我的解决方案:
let instanceOne = null;
class One {
constructor(brandNewInstance = false) {
if (instanceOne && !brandNewInstance) return instanceOne;
this.name = 'one';
if (brandNewInstance) return this;
instanceOne = this;
return instanceOne;
}
method() {
console.log('Method in one');
}
}
let instanceTwo = null;
class Two extends One {
constructor() {
super(true);
if (instanceTwo) return instanceTwo;
this.name = 'two';
instanceTwo = this;
return instanceTwo;
}
method() {
console.log('Method in two');
}
}
我使用node.js v6.9.1
答案 0 :(得分:1)
这是因为这一行:
if (instanceOne) return instanceOne;
One
构造函数在上面的代码中运行两次。第二个One
来电是super()
,在这种情况下,this
是从Two.prototype
创建的,对象方法是Two.prototype.method
。
从super()
替换this
并使用One
单例返回语句,然后Two
构造函数只修改One
单例实例。
可以使用静态属性来保存实例:
constructor() {
if (this.constructor.hasOwnProperty('instance'))
return this.constructor.instance;
this.constructor.instance = this;
this.name = 'one';
}
或者,如果与子类共享实例是预期的行为,
constructor() {
if ('instance' in this.constructor)
return this.constructor.instance;
this.name = 'one';
this.constructor.instance = this;
}
在这种情况下,所有单例机制都由One
构造函数完成,Two
只需要调用super
:
constructor() {
super();
this.name = 'two';
}
此外,结束return
语句是多余的。 this
不必明确返回。
答案 1 :(得分:1)
你做的事情有点奇怪。 ecmascript 6中的构造函数和子类不会以您认为的方式工作。您可能希望阅读this blog post(特别是第4节)以了解更多信息。
从那篇文章中可以看出,你的代码看起来就像这样:
Reflect.construct
(new.target是作为Two
的第三个参数传递的值)
您可以看到Two.prototype
类没有创建新对象,并且未使用One
。相反,"DOMPDF_ENABLE_JAVASCRIPT" => true
单例实例被使用和变异。