检查对象是不是是类的“直接实例”

Posted

技术标签:

【中文标题】检查对象是不是是类的“直接实例”【英文标题】:Check if object is a 'direct instance' of a class检查对象是否是类的“直接实例” 【发布时间】:2018-08-31 05:00:13 【问题描述】:

我有两个班级:

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 实例的地方有效。 【参考方案1】:

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

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

【讨论】:

@Sacha 请查看我的答案以对其他类进行通用检查【参考方案2】:

检查构造函数:

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

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

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

【讨论】:

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

问题是您引用的所有类都是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 中没有? 你永远不应该比较类的名称。它们可能被缩小器破坏,它们可能被优化掉,它们可能被覆盖或伪造。永远不要依赖名字。【参考方案4】:

您可以使用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);

【讨论】:

【参考方案5】:

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

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

【讨论】:

【参考方案6】:

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

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

【讨论】:

以上是关于检查对象是不是是类的“直接实例”的主要内容,如果未能解决你的问题,请参考以下文章

Python 检查类的实例

Python检查类的实例

Java试卷问题,实在不会,希望各位帮帮忙

什么是类的实例

python元类深入解析

面向对象编程进阶版