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

问题描述 投票:22回答:4

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

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

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

并从另一个模块导入它:

import {Thingy} from "thingy";

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

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

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

javascript class prototype ecmascript-6
4个回答
14
投票

我会在前面说清楚,任何任意函数都可以是构造函数。如果您区分“类”和“功能”,那么您的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而不是类,该怎么办?


27
投票

如果要确保该值不仅是一个函数,而且实际上是一个类的构造函数,您可以将该函数转换为字符串并检查其表示形式。 The spec dictates the string representation of a class constructor

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;
  }
}

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


0
投票

也许这可以帮助

let is_class = (obj) => {
    try {
        new obj();
        return true;
    } catch(e) {
        return false;
    };
};

-1
投票

关于什么:

function isClass(v) {
   return typeof v === 'function' && v.prototype.constructor === v;
}
© www.soinside.com 2019 - 2024. All rights reserved.