【问题标题】:What is the difference between instanceof Parent and instanceof super.constructor?instanceof Parent 和 instanceof super.constructor 有什么区别?
【发布时间】:2021-01-12 21:51:26
【问题描述】:

我有一个类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))
  }
}

【问题讨论】:

  • 我认为this.constructorChild 而不是Parent。 --- 另外,示例中没有使用super.constructor
  • 在我的情况下,父母实际上是匿名的” - 只需解决这个问题,以便您可以编写 instanceof Parent,这就是您想要的并且可以工作。
  • 请向我们展示您使用匿名类的实际代码以及为什么需要它来解决您的实际问题。鉴于您之前的问题,似乎这种方法只会导致问题。
  • 所以instanceof Parent 会起作用。但是,如果我理解正确,您理想情况下会想写instanceof X?当然,即使目前没有什么能阻止你写const X = (c => { … })(class local { constructor(p) { if (p instanceof local) console.log("got Parent/X instance"); } });
  • "我正在包装我的类定义,这样我就可以在没有 new 的情况下创建一个新实例。" - 这是一个非常基本的包装,我不明白你为什么只复制静态方法。你会想看看the tricks shown/mentioned in this answer

标签: javascript class oop instanceof


【解决方案1】:

首先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");
    }
  }
}

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

检查instanceof 值的代码得到的结果与预期一致:

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

  2. Child 使用提供的参数调用超级构造函数,格式如下:

      super([Parent Object])
    

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

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

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

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

【讨论】:

  • 谢谢,这让我明白了。我知道我不应该这样做,我唯一(迂腐的)担心是我确实认为 X 和 Parent 是同一件事(而 Parent 实际上只是被存储,因为它是 Child 定义所必需的)和很难分别命名它们。
  • 我的意思是,我最初设计的包装函数甚至不返回父定义,而是完全隐藏它;但我想即使那样,在本地分配一个名称也没有什么坏处,就像上面建议的 [local]。
猜你喜欢
  • 2010-10-04
  • 1970-01-01
  • 2019-04-05
  • 2011-01-28
  • 1970-01-01
  • 2013-08-06
  • 2010-10-28
  • 2014-04-12
  • 2015-07-28
相关资源
最近更新 更多