Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/388.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何检查变量是否是ES6类声明?_Javascript_Class_Prototype_Ecmascript 6 - Fatal编程技术网

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

Javascript 如何检查变量是否是ES6类声明?,javascript,class,prototype,ecmascript-6,Javascript,Class,Prototype,Ecmascript 6,我正在从一个模块导出以下ES6类: export class Thingy { hello() { console.log("A"); } world() { console.log("B"); } } 并从另一个模块导入: import {Thingy} from "thingy"; if (isClass(Thingy)) { // Do something... } 如何检查变量是否为类?不是类实例,而是类声明 换句话说,在上面的示例中,我将如何

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

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

  world() {
    console.log("B");
  }
}
并从另一个模块导入:

import {Thingy} from "thingy";

if (isClass(Thingy)) {
  // Do something...
}
如何检查变量是否为类?不是类实例,而是类声明


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

我将在前面说明,任何任意函数都可以是构造函数。如果你在区分“类”和“函数”,你就在做糟糕的API设计选择。例如,如果您假定某个对象必须是
,那么使用Babel或Typescript的任何人都不会被检测为
,因为他们的代码将被转换为函数。这意味着您要求所有使用您的代码库的人通常都必须在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 isClass(v) {
  if (typeof v !== 'function') {
    return false;
  }
  try {
    v();
    return false;
  } catch(error) {
    if (/^Class constructor/.test(error.message)) {
      return true;
    }
    return false;
  }
}
缺点是调用函数可能会产生各种未知的副作用…

那么:

function isClass(v) {
   return typeof v === 'function' && v.prototype.constructor === v;
}
也许这会有帮助

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

我们将仔细阅读一些答案,并考虑@Joe Hildebrand突出边缘案例,因此以下解决方案将更新以反映大多数尝试过的边缘案例。在边缘案例可能存在的地方,可以进行更多识别

关键洞察:虽然我们正在进入类,但就像JS中的指针和引用一样,争论并没有证实其他语言的所有特性——JS本身并不像我们在其他语言构造中那样有类

有些人认为这是函数的糖衣语法,有些人则持其他观点。我相信,课程在本质上仍然是一种功能,但与其说是糖衣功能,不如说是可以添加类固醇的功能。类将做函数不能做或没有麻烦升级它们来做的事情

因此,暂时将类作为函数处理会打开另一个潘多拉盒子。JS中的一切都是对象,JS不理解但愿意与开发人员合作的一切都是对象

  • 布尔可以是对象(如果使用新关键字定义)
  • 数字可以是对象(如果使用新关键字定义)
  • 字符串可以是对象(如果使用new关键字定义)
  • 日期总是对象
  • 数学永远是对象
  • 正则表达式始终是对象
  • 数组始终是对象
  • 函数始终是对象
  • 对象始终是对象
那么什么是类呢? 重要类是用于创建对象的模板。此时,它们不是对象本身。 当您在某个地方创建类的实例时,它们将成为对象,该实例将被视为对象。 所以我们需要筛选出

  • 我们正在处理哪种类型的对象
  • 然后我们需要筛选出它的属性
  • 函数始终是对象,它们始终具有原型和属性参数
  • arrow函数实际上是老式函数的糖衣,没有这个或更多简单返回上下文的概念,因此即使您试图定义它们,也没有原型或参数
  • 类是一种可能函数的蓝图,没有arguments属性,但有原型。这些原型在实例中成为事实之后的对象
所以我试图捕获并记录我们检查的每个迭代,当然还有结果

希望这有帮助

“严格使用”;
风险等级为AA、AAA、BB、BBB、BBBB、DD、DDD、E、F;
isclass=函数(a){
if(/null | undefined/.test(a))返回false;
让类型=a的类型;
让props=Object.getOwnPropertyNames(a);
log(`type:${types}props:${props}`);
返回((!props.includes('arguments')&&props.includes('prototype'));}
A类{};
B类{建造商(品牌){
this.carname=brand;}};
函数C(){};
职能D(a){
这个.a=a;};
AA=A;
AAA=新的A;
BB=B;
BBB=新的B;
BBBB=新的B(“检查”);
DD=D;
DDD=新的D(“支票”);
E=(a)=>a;
F=类{};
console.log('和A是类:'+isclass(A)+'\n'+'----
let is_class = (obj) => {
    try {
        new obj();
        return true;
    } catch(e) {
        return false;
    };
};