首页 > 解决方案 > Determine closest ancestor between list of classes

问题描述

Consider this example:

class Point {}
class Point2D extends Point {}
class Point3D extends Point2D {}
class FloatPoint extends Point {}

class Bar {}
class Foo extends Bar {}

const result = joinWithClosestAncestor([Point, Point2D, Point3D, FloatPoint, Bar, Foo])
// result === [[Point], [Point2D, Point], [Point3D, Point2D], [FloatPoint, Point], [Bar], [Foo, Bar]];

I'm trying to create joinWithClosestAncestor which takes an array of classes and returns an array of pairs where the first element is the class & the second is the closest ancestor of the class (if any) from the input classes.

In the example Point3D is derived from Point through Point2D, but because Point2D is in the input list & is closer related to Point3D than Point, it is instead chosen. I can use Class.prototype instanceof X to determine if it's related or not but I can't compare the depth of the relation.

Is there a way to somehow compare the depth of instanceof between different classes to always get the CLOSEST relation? Or any other way?

标签: javascripttypescriptclassoopinheritance

解决方案


您可以Object.getPrototypeOf()在类构造函数上使用来获取其直接超类构造函数。它找不到明显的 MDN 源代码,但Axel Rauschmayer 博士为不耐烦的程序员编写的 JavaScript解释说,发生这种情况是为了让static子类继承属性和方法。

无论如何,由于您可以找到直接的超类构造函数,因此您可以沿着该链向上走,直到找到存在于您的数组中的某些东西,或者直到您离开链的末端。像这样的东西,例如:

function joinWithClosestAncestor(ctors: Array<new (...args: any) => any>) {
  const ret = [];
  for (let ctor of ctors) {
    const cur = [ctor];
    ret.push(cur);
    for (
      let parent = Object.getPrototypeOf(ctor);
      parent;
      parent = Object.getPrototypeOf(parent)
    ) {
      if (ctors.includes(parent)) {
        cur.push(parent);
        break;
      }
    }
  }
  return ret;
}

它产生了您正在寻找的结果,至少对于您给出的示例:

const result = joinWithClosestAncestor([Point, Point2D, Point3D, FloatPoint, Bar, Foo])
console.log(JSON.stringify(result.map(x => x.map(y => y.name))));
// [["Point"],["Point2D","Point"],["Point3D","Point2D"],
//  ["FloatPoint","Point"],["Bar"],["Foo","Bar"]]

Playground 代码链接


推荐阅读