【问题标题】:Check if object is a 'direct instance' of a class检查对象是否是类的“直接实例”
【发布时间】:2021-11-20 14:51:40
【问题描述】:

我有两个班级:

class Bar extends Foo { // Foo isn't relevant
  constructor(value) {
    if (!(value instanceof Foo)) throw "InvalidArgumentException: (...)";
    super();
    this.value = value;
  }
}

class Baz extends Bar {
  constructor(value) {
    super(value);
  }
}

Bar constructor 检查value 是否是 Foo 的实例,如果不是则抛出错误。至少,这就是我想要它做的。如果您传递 BarBaz 作为值,则 if 语句也会返回 true。目标是只让Foos 通过。
我已经找到了this answer,但这并没有真正回答我的问题。

【问题讨论】:

  • This answer 来自您链接的其他问题似乎有效。只有使用 new Foo() 创建的 Foo 对象在调用 foo.constructor.name 时会返回“Foo”
  • 你认为你需要这个做什么?您似乎在滥用继承,因为您的目标是破坏Liskov Substitution Principle。不要那样做。每个BarBaz 实例都应该在您希望拥有Foo 实例的地方有效。

标签: javascript class object instance subclass


【解决方案1】:

检查构造函数:

if (!value || value.constructor !== Foo)
  throw 'InvalidArgumentException: (...)';

或对象的原型(这更类似于instanceof 所做的):

if (!value || Object.getPrototypeOf(value) !== Foo.prototype)
  throw 'InvalidArgumentException: (...)';

【讨论】:

  • 这没有回答核心问题。它没有解决继承问题。
【解决方案2】:

您可以使用Object.getPrototypeOf(yourObj)Foo.prototype 之间的比较来查看yourObj 是否正是Foo 的一个实例。您只需继续为每个级别调用Object.getPrototypeOf,就可以向上移动。

例子:

class Foo {}

class Bar extends Foo {}
class Baz extends Bar {}

const foo = new Foo();
const bar = new Bar();
const baz = new Baz();

// For this function:
// - level 0 is self
// - level 1 is parent
// - level 2 is grandparent
// and so on.
function getPrototypeAt(level, obj) {
    let proto = Object.getPrototypeOf(obj);
    while (level--) proto = Object.getPrototypeOf(proto);
    return proto;
}

console.log("bar is a foo:", bar instanceof Foo);
console.log("baz is a foo:", baz instanceof Foo);
console.log("foo is exactly a foo:", getPrototypeAt(0, foo) === Foo.prototype);
console.log("bar is exactly a foo:", getPrototypeAt(0, bar) === Foo.prototype);
console.log("bar is direct child of foo:", getPrototypeAt(1, bar) === Foo.prototype);
console.log("baz is direct child of foo:", getPrototypeAt(1, baz) === Foo.prototype);
console.log("baz is direct child of bar:", getPrototypeAt(1, baz) === Bar.prototype);
console.log("baz is grandchild of foo:", getPrototypeAt(2, baz) === Foo.prototype);

【讨论】:

    【解决方案3】:

    您应该测试value 的内部[[Prototype]] 是否正好是Foo.prototype。您可以通过Object.getPrototypeOf 获取内部[[Prototype]]

    if ( Object.getPrototypeOf( value ) !== Foo.prototype )
       throw "InvalidArgumentException: (...)";
    

    【讨论】:

      【解决方案4】:

      如果你知道所有你可以使用的类

      if(!(value instanceof Foo && !(value instanceof Bar) && !(value instanceof Baz)))
      

      【讨论】:

      • @Sacha 请查看我的答案以对其他类进行通用检查
      【解决方案5】:

      我创造了检查 DOM 类和元素之间关系的函数

      const getCreator = instance => Object.getPrototypeOf(instance).constructor.name;
      // usage
      getCreator(document.documentElement) === "HTMLHtmlElement;
      

      【讨论】:

        【解决方案6】:

        问题是您引用的所有类都是Foo 的后代。这样new Baz() instanceOf Bar && new Bar() instanceOf Foo === true。 所以当你问的是 Bar instanceOf Foo 时,通过继承就会为真。

        由于 JS 中没有 Java getClass() 等价物,您应该使用类似:

        if (value.constructor.name !== Foo.name)
        

        【讨论】:

        • Java 中的 getClass() 做了什么而 value.constructor 在 JS 中没有?
        • 你不应该比较类的名称。它们可能被缩小器破坏,它们可能被优化掉,它们可能被覆盖或伪造。永远不要依赖名字。
        猜你喜欢
        • 1970-01-01
        • 2013-05-17
        • 2016-07-07
        • 2021-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多