web-dev-qa-db-ja.com

ES6クラスの継承チェーンを使用するインスタンスが機能しない

ES6 class構文を使用して、継承のチェーンが複数あるのに、なぜinstanceof演算子が継承チェーンに対して機能しないのか疑問に思いますか?

(オプションの読み取り)

instanceof演算子はどのように機能しますか?

_obj instanceof Constructor_では、instanceof演算子は、Constructor関数の_'prototype'_プロパティがプロトタイプobjのチェーン。存在する場合は、trueを返します。それ以外の場合は、false


次のスニペットでは、BTErrorError1。)から継承します。 SomeErrorBTErrorから拡張されます(3。)。
しかし、(4。)からわかるように、instanceof演算子の結果はfalse for new SomeError() instanceof BTErrorこれは私の理解ではtrueである必要があります。

_class BTError extends Error {}
console.log('1.', Reflect.getPrototypeOf(BTError.prototype) === Error.prototype); // 1. true
console.log('2.', new BTError() instanceof Error); // 2. true

console.log('');

class SomeError extends BTError {}
console.log('3.', Reflect.getPrototypeOf(SomeError.prototype) === BTError.prototype); // 3. true
console.log('4.', new SomeError() instanceof BTError); // 4. false

console.log('');

class SpecificError extends SomeError {}
console.log('5.', Reflect.getPrototypeOf(SpecificError.prototype) === SomeError.prototype); // 5. true
console.log('6.', new SpecificError() instanceof Error); // 6. true
console.log('7.', new SpecificError() instanceof BTError); // 7. false
console.log('8.', new SpecificError() instanceof SomeError); // 8. false_

質問

私が理解できない、またはinstanceof演算子が奇妙なを実行しているだけの重要なものはありますか?

11
abhisekp

あなたの例の最後の部分に焦点を当てる

BabelJSを使用してこのコードを変換し、互換性を持たせています

class BTError extends Error {}
class SomeError extends BTError {}
class SpecificError extends SomeError {}

console.log('6.', new SpecificError() instanceof Error);
console.log('7.', new SpecificError() instanceof BTError);
console.log('8.', new SpecificError() instanceof SomeError);

これは上記のコードのトランスパイルバージョンです

'use strict';

function _classCallCheck(instance, Constructor) {
    if (!(instance instanceof Constructor)) {
        throw new TypeError("Cannot call a class as a function");
    }
}

function _possibleConstructorReturn(self, call) {
    if (!self) {
        throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
    }
    return call && (typeof call === "object" || typeof call === "function") ? call : self;
}

function _inherits(subClass, superClass) {
    if (typeof superClass !== "function" && superClass !== null) {
        throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
    }
    subClass.prototype = Object.create(superClass && superClass.prototype, {
        constructor: {
            value: subClass,
            enumerable: false,
            writable: true,
            configurable: true
        }
    });
    if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}

var BTError = function(_Error) {
    _inherits(BTError, _Error);

    function BTError() {
        _classCallCheck(this, BTError);

        return _possibleConstructorReturn(this, (BTError.__proto__ || Object.getPrototypeOf(BTError)).apply(this, arguments));
    }

    return BTError;
}(Error);

var SomeError = function(_BTError) {
    _inherits(SomeError, _BTError);

    function SomeError() {
        _classCallCheck(this, SomeError);

        return _possibleConstructorReturn(this, (SomeError.__proto__ || Object.getPrototypeOf(SomeError)).apply(this, arguments));
    }

    return SomeError;
}(BTError);

var SpecificError = function(_SomeError) {
    _inherits(SpecificError, _SomeError);

    function SpecificError() {
        _classCallCheck(this, SpecificError);

        return _possibleConstructorReturn(this, (SpecificError.__proto__ || Object.getPrototypeOf(SpecificError)).apply(this, arguments));
    }

    return SpecificError;
}(SomeError);

console.log('6.', new SpecificError() instanceof Error); // 6. true
console.log('7.', new SpecificError() instanceof BTError); // 7. false
console.log('8.', new SpecificError() instanceof SomeError); // 8. false

この問題は、_inheritに直接割り当てるのではなく、それと別のデフォルトプロパティのセットをマージして作成されたオブジェクトをsubClass.prototypeに割り当てるsuperClass.prototypeメソッドに起因すると思います。

このプロトタイプのチェーンでは、継承は機能しますが、instanceof演算子は参照によってそれを移動できないため、falseを期待する場所にtrueを取得します。

どうやら、 このバグレポート によると、これは既知の予想される動作(つまり制限)であり、考えられる回避策は babel-plugin-transform-b​​uiltin-extend を使用することです。

7
alebianco