这里我先说清楚,任意函数都可以是构造函数。如果您要区分“类”和“函数”,那么您的 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 而不是类怎么办?