如何检查变量是否是 ES6 类声明?

新手上路,请多包涵

我正在从一个模块中导出以下 ES6 类:

 export class Thingy {
  hello() {
    console.log("A");
  }

  world() {
    console.log("B");
  }
}

并从另一个模块导入它:

 import {Thingy} from "thingy";

if (isClass(Thingy)) {
  // Do something...
}

如何检查一个变量是否是一个类?不是类 _实例_,而是类 _声明_?

换句话说,我将如何实现上例中的 isClass 函数?

原文由 XåpplI‘-I0llwlg’I - 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 375
2 个回答

我会在这里先说清楚,任何任意函数都可以是构造函数。如果您区分“类”和“函数”,那么您的 API 设计选择很糟糕。如果你假设某些东西必须是 class 例如,没有人使用 Babel 或 Typescript 将被检测为 class 因为他们的代码将被转换为函数。这意味着您强制要求任何使用您的代码库的人通常 必须 在 ES6 环境中运行,因此您的代码将无法在旧环境中使用。

您在此处的选项仅限于实现定义的行为。在 ES6 中,一旦解析了代码并处理了语法,就没有太多类特定的行为了。你所拥有的只是一个构造函数。你最好的选择是做

if (typeof Thingy === 'function'){
  // It's a function, so it definitely can't be an instance.
} else {
  // It could be anything other than a constructor
}

如果有人需要执行非构造函数,请为此公开一个单独的 API。

显然,这不是您要寻找的答案,但明确这一点很重要。

正如这里提到的另一个答案,你确实有一个选择,因为 .toString() 函数需要返回一个类声明,例如

class Foo {}
Foo.toString() === "class Foo {}" // true

然而,关键是只有 在可以 的情况下才适用。实现 100% 符合规范

class Foo{}
Foo.toString() === "throw SyntaxError();"

目前没有 浏览器 这样做,但是有几个嵌入式系统专注于 JS 编程,例如,为了保留程序本身的内存,它们在解析后丢弃源代码,这意味着它们将没有源代码可以返回 .toString() 这是允许的。

类似地,通过使用 .toString() 您正在对未来验证和通用 API 设计做出假设。说你愿意

const isClass = fn => /^\s*class/.test(fn.toString());

因为这依赖于字符串表示,所以很容易崩溃。

以装饰器为例:

 @decorator class Foo {}
Foo.toString() == ???

.toString() 是否包括装饰器?如果装饰器本身返回一个 function 而不是一个类怎么办?

原文由 loganfsmyth 发布,翻译遵循 CC BY-SA 4.0 许可协议

如果您想确保该值不仅是一个函数,而且确实是一个类的构造函数,您可以将该函数转换为字符串并检查其表示形式。 该规范规定了类构造函数的字符串表示形式

 function isClass(v) {
  return typeof v === 'function' && /^\s*class\s+/.test(v.toString());
}


另一种解决方案是尝试将值作为普通函数调用。类构造函数不能像普通函数一样调用,但错误消息可能因浏览器而异:

 function isClass(v) {
  if (typeof v !== 'function') {
    return false;
  }
  try {
    v();
    return false;
  } catch(error) {
    if (/^Class constructor/.test(error.message)) {
      return true;
    }
    return false;
  }
}

缺点是调用该函数可能会产生各种未知的副作用……

原文由 Felix Kling 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题