instanceof Parent 和 instanceof super.constructor 有什么区别?

问题描述

我有一个Parent一个扩展 Child 的类 Parent。 在 Parent 的构造函数中,我现在需要确定 x 是原始类的实例还是子类的实例。

就我而言,Parent 实际上是匿名的,我使用的 instanceof of this.constructor 没有按预期工作:

class Parent {
  constructor(x) {
    if (x instanceof this.constructor) {
      console.log("x is instanceof of this.constructor");
    }
    if (x instanceof Parent) {
      console.log("x is instanceof of Parent");
    }
  }
}

class Child extends Parent {
  constructor(x) {
    super(x);
  }
  foo(x) {
    new this.constructor(new super.constructor(x))
  }
}

打电话

new Child().foo()

现在产生 x is instanceof of Parent 而不是 x is instanceof of this.constructor。我做错了什么,如何在不使用 x is instanceof of *Parent* 的情况下解决此问题?


这一切的原因是我包装了我的类定义,以便我可以在没有 new 的情况下创建一个新实例。该类在包装/变异后分配给 Parent,因此包装的类应该是匿名的。

我不知道这是否有意义,我简化的示例可能无法说明这一切的意义所在,但除了上面解释的一个问题之外,它实际上非常方便:

X()   // create new instance of Parent without new
X.f   // access static methods
const { X,c: Parent } = function (c) {
    return {
        X: Object.assign(
            function () {
                return new c(...arguments);
            },_.pick(c,Object.getownPropertyNames(c)  // using lodash here
                .filter(n => typeof c[n] === "function")
            )
        ),c
    };
}(class {
  constructor(x) {
    if (x instanceof this.constructor) {
      console.log("x is instanceof of this.constructor");
    }
    if (x instanceof Parent) {
      console.log("x is instanceof of Parent");
    }
  }
})

class Child extends Parent {
  constructor(x) {
    super(x);
  }
  foo(x) {
    new this.constructor(new super.constructor(x))
  }
}

解决方法

首先ParentChild标识符的绑定是Parent和Child类的构造函数和常量。当用作 Object.assign 的第一个参数时,Parent 绑定尚未创建但是在将方法分配给函数 c 时,该函数实际上不是叫。因此,稍后在调用类构造函数代码时,ParentChild 变量均引用相应的类构造函数。

因此

class {
  constructor(x) {
    if (x instanceof Parent) {
      console.log("x is instanceof of Parent");
      if( x instance of Child) {
      console.log("x is instance of Child");
    }
  }
}

应指明参数是 ParentChild 的实例。当然因为类扩展把Parent.prototype放在Child.prototype的继承链的头部,所以Child的每一个实例也是Parent的一个实例。

从代码检查 instanceof 值中获得的结果符合预期:

  1. foo 创建一个 [Object Parent] 对象参数以传递给 Child 构造函数

  2. Child 使用以下形式提供的参数调用超级构造函数:

      super([Parent Object])
    

    但是 this 看到的 super 值设置为新的 Child 对象实例。

  3. 在超级构造函数中,[Object Parent] x 参数不是 this.constructor 的实例,它是 Child,因此不会生成这样的消息。

您可能希望看看是否可以通过使用较少的复杂性来简化完整的代码,遵循以下结构线:

 class Parent {..........}
 class Child extends Parent {.....}
 const X = Object.assign(.......)