使用ES6类的instanceof继承链不起作用

时间:2017-02-06 09:36:08

标签: javascript class inheritance ecmascript-6 es6-class

使用ES6 class语法,我想知道为什么当有多个继承链时,instanceof运算符不适用于继承链?

  (可选阅读)      
    

instanceof运营商如何运作?

         

obj instanceof Constructor中,instanceof运算符会检查'prototype'函数的Constructor属性是否存在于{em> prototype 链中{ {1}}。如果存在,请返回obj。否则,true

  
     

在以下代码段中,false继承自BTError 1。 ),Error延伸自{{1} ( 3。 ) 但正如我们可以从( 4。 )中看到的那样,SomeError运算符为BTError生成了instanceof,我的理解应该是false

new SomeError() instanceof BTError

问题

有什么非平凡的我无法理解,或者true操作员只是表现怪异的

3 个答案:

答案 0 :(得分:5)

专注于你的例子的最后一部分

您正在使用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

显然,根据this bug report,这是已知和预期的行为(即限制),可能的解决方法是使用babel-plugin-transform-builtin-extend

答案 1 :(得分:2)

使用TypeScript遇到此问题。通过在超级调用之后在类构造函数中添加以下内容来解决此问题:

Object.setPrototypeOf(this, YOUR_CLASS_HERE.prototype);

不确定是否对您有帮助。

答案 2 :(得分:1)

在我的情况下,instanceof在将编译目标设置为“ es5”的情况下不起作用。更改为“ es6”后,将产生正确的结果。