Javascript 如何检查变量是否是ES6类声明?
我正在从一个模块导出以下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... } 如何检查变量是否为类?不是类实例,而是类声明 换句话说,在上面的示例中,我将如何
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;
};
};