1

シングルトン パターンを使用して、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を使用しています

4

2 に答える 2

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 は の 3 番目の引数として渡される値ですReflect.construct)

Twoこのクラスでは、新しいオブジェクトが作成されておらず、使用されていないことがわかりますTwo.prototype。代わりに、Oneシングルトン インスタンスが使用され、変更されます。

于 2016-10-27T14:15:38.823 に答える