如何识别函数是 class 构造函数以及如何将其作为函数调用?
How to recognize the function is the class constructor and how to call it as a function?
我对 es2016 中的 class
功能有点困惑,尽管与 function
相比,它被认为只是创建 classes 的语法糖和 prototype
,但在某些情况下的行为是不同的,特别是 - classes 不能像函数一样被调用,而且似乎无法确定函数是否是 class 构造函数或简单函数,不使用 toString
和 /^class/
RegExp
.
假设例子:
class Foo {
constructor () {
this.name = 'foo';
}
}
function Bar () {
this.name = 'bar';
}
function doSmth (anyArg) {
if (typeof anyArg === 'function') {
var obj = { someProp: 'qux' };
anyArg.call(obj);
return obj;
}
// ...
}
doSmth(Bar);
doSmth(Foo); // Class constructor Foo cannot be invoked without 'new'
是typeof 'function'
,但是不能作为函数来调用!好的。
这是我的 2 个问题:
- 有没有什么方法可以调用
Foo
构造函数,就像 Bar
一样,覆盖 this
上下文?
- 有什么方法可以检测到
anyArg
是 class 的构造函数,以便我可以在 doSmth
函数中以不同方式处理它。没有 toString
和 RegExp
( 因为在这种情况下性能损失会很大 )。然后我可以使用 Reflect.construct
初始化新实例,并使用 Object.assign
使用实例中的值扩展我的 obj
变量。
谢谢你,亚历克斯
我不知道有什么方法可以完成您在第一个问题中提出的问题。
对于第二个问题,其实你自己找到了一个区分的方法。 class 构造函数和用作构造函数的函数之间的区别之一是前者在不使用 new
关键字时会出错,而后者则不会。
所以,如果我们使用 try/catch,我们可以大致实现您的要求:
class Foo {
constructor () {
this.name = 'foo';
}
}
function Bar () {
this.name = 'bar';
}
function doSmth (anyArg) {
if (typeof anyArg === 'function') {
var obj = { someProp: 'qux' };
try {
anyArg.call(obj);
} catch(e) {
var x = Reflect.construct(anyArg, []);
Object.assign(obj, x);
}
return obj;
}
}
doSmth(Bar);
doSmth(Foo);
需要说明的是,我并不是说这是一个好主意、好代码,或者它具有您正在寻找的性能,但我想我要指出的是这种可能性确实存在。
两个问题都否。
下面是 Angular 1.x 检测 类 的方法:
function isClass(func) {
// IE 9-11 do not support classes and IE9 leaks with the code below.
if (msie <= 11 || typeof func !== 'function') {
return false;
}
var result = func.$$ngIsClass;
if (!isBoolean(result)) {
// Support: Edge 12-13 only
// See: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6156135/
result = func.$$ngIsClass = /^(?:class\b|constructor\()/.test(stringifyFn(func));
}
return result;
}
不幸的是,这是最好的解决方案。它甚至在 Firefox 中都不起作用。
如果您担心 RegEx 的性能损失,请使用 substring()
。如果您仍然担心字符串操作的性能,那么请考虑另一种实际上区分函数类型的语言。在 JavaScript 他们都是 function
.
class Foo {
constructor() {
this.name = 'foo';
}
}
function Bar() {
this.name = 'bar';
}
function doSmth(anyArg) {
if (typeof anyArg === 'function') {
var obj = {
someProp: 'qux'
};
if (anyArg.toString().substring(0, 5) === 'class') {
Object.assign(obj, new anyArg());
} else {
anyArg.call(obj);
}
return obj;
}
// ...
}
var bar = doSmth(Bar);
var foo = doSmth(Foo);
console.log(bar);
console.log(foo);
我对 es2016 中的 class
功能有点困惑,尽管与 function
相比,它被认为只是创建 classes 的语法糖和 prototype
,但在某些情况下的行为是不同的,特别是 - classes 不能像函数一样被调用,而且似乎无法确定函数是否是 class 构造函数或简单函数,不使用 toString
和 /^class/
RegExp
.
假设例子:
class Foo {
constructor () {
this.name = 'foo';
}
}
function Bar () {
this.name = 'bar';
}
function doSmth (anyArg) {
if (typeof anyArg === 'function') {
var obj = { someProp: 'qux' };
anyArg.call(obj);
return obj;
}
// ...
}
doSmth(Bar);
doSmth(Foo); // Class constructor Foo cannot be invoked without 'new'
是typeof 'function'
,但是不能作为函数来调用!好的。
这是我的 2 个问题:
- 有没有什么方法可以调用
Foo
构造函数,就像Bar
一样,覆盖this
上下文? - 有什么方法可以检测到
anyArg
是 class 的构造函数,以便我可以在doSmth
函数中以不同方式处理它。没有toString
和RegExp
( 因为在这种情况下性能损失会很大 )。然后我可以使用Reflect.construct
初始化新实例,并使用Object.assign
使用实例中的值扩展我的obj
变量。
谢谢你,亚历克斯
我不知道有什么方法可以完成您在第一个问题中提出的问题。
对于第二个问题,其实你自己找到了一个区分的方法。 class 构造函数和用作构造函数的函数之间的区别之一是前者在不使用 new
关键字时会出错,而后者则不会。
所以,如果我们使用 try/catch,我们可以大致实现您的要求:
class Foo {
constructor () {
this.name = 'foo';
}
}
function Bar () {
this.name = 'bar';
}
function doSmth (anyArg) {
if (typeof anyArg === 'function') {
var obj = { someProp: 'qux' };
try {
anyArg.call(obj);
} catch(e) {
var x = Reflect.construct(anyArg, []);
Object.assign(obj, x);
}
return obj;
}
}
doSmth(Bar);
doSmth(Foo);
需要说明的是,我并不是说这是一个好主意、好代码,或者它具有您正在寻找的性能,但我想我要指出的是这种可能性确实存在。
两个问题都否。
下面是 Angular 1.x 检测 类 的方法:
function isClass(func) {
// IE 9-11 do not support classes and IE9 leaks with the code below.
if (msie <= 11 || typeof func !== 'function') {
return false;
}
var result = func.$$ngIsClass;
if (!isBoolean(result)) {
// Support: Edge 12-13 only
// See: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6156135/
result = func.$$ngIsClass = /^(?:class\b|constructor\()/.test(stringifyFn(func));
}
return result;
}
不幸的是,这是最好的解决方案。它甚至在 Firefox 中都不起作用。
如果您担心 RegEx 的性能损失,请使用 substring()
。如果您仍然担心字符串操作的性能,那么请考虑另一种实际上区分函数类型的语言。在 JavaScript 他们都是 function
.
class Foo {
constructor() {
this.name = 'foo';
}
}
function Bar() {
this.name = 'bar';
}
function doSmth(anyArg) {
if (typeof anyArg === 'function') {
var obj = {
someProp: 'qux'
};
if (anyArg.toString().substring(0, 5) === 'class') {
Object.assign(obj, new anyArg());
} else {
anyArg.call(obj);
}
return obj;
}
// ...
}
var bar = doSmth(Bar);
var foo = doSmth(Foo);
console.log(bar);
console.log(foo);