单例inheritanceBuggy行为

我已经发现在使用Singleton模式的JavaScript es6inheritance中的马车行为。

代码是

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 

不知何故,遗产被搞砸了。 这里属性被覆盖而不是对象方法。

我的问题是为什么它正在工作(像现在扔),你能解释这种行为?

看来新对象需要全新的对象作为父对象(参见下面的解决scheme)。


如果你遇到同样的问题,这里是我的解决scheme:

 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

你做的事有点奇怪 ecmascript 6中的构造函数和子类不以您认为的方式工作。 您可能希望阅读这篇博文 (特别是第4部分)以了解更多信息。

从这篇文章中,你的代码看起来像这样:

 let instanceOne = null; function One() { // var this = Object.create(new.target.prototype); // under the hood if (instanceOne) return instanceOne; this.name = 'one'; instanceOne = this; return instanceOne; } One.prototype.method = function() { console.log('Method in one'); } let instanceTwo = null; function Two() { var that = undefined; that = Reflect.construct(One, [], new.target); if (instanceTwo) return instanceTwo; that.name = 'two'; instanceTwo = that; return instanceTwo; } Two.prototype.method = function() { console.log('Method in two'); } Object.setPrototypeOf(Two, One); Object.setPrototypeOf(Two.prototype, One.prototype); const objOne = Reflect.construct(One, [], One); const objTwo = Reflect.construct(Two, [], Two); console.log(objOne.name); console.log(objTwo.name); objOne.method(); objTwo.method(); 

(new.target是作为Reflect.construct的第三个parameter passing的值)

你可以看到对于Two类,没有新的对象被创build,并且Two.prototype没有被使用。 相反, One单例实例被使用和变异。

这是因为这一行:

  if (instanceOne) return instanceOne; 

One构造函数在上面的代码中运行两次。 第二Onesuper()this是从Two.prototype创build的,object是Two.prototype.method

super()返回语句用One单例replace,然后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不一定要明确地返回。