Testing if something is a class in javascript
Here's a quick and dirty way to determine if you have a class or a function.
function myFunc() { };
class MyClass() { };
Object.getOwnPropertyNames(myFunc);
// -> [ 'length', 'name', 'arguments', 'caller', 'prototype' ]
Object.getOwnPropertyNames(MyClass);
// -> [ 'length', 'prototype', 'name' ]
So we know we have a function and not a class if arguments
is a property name:
Object.getOwnPropertyNames(myFunc).includes('arguments');
// -> true
Object.getOwnPropertyNames(MyClass).includes('arguments');
// -> false
Arrow functions and aysnc
functions won't have an arguments
property name or a prototype
. A more complete example might look like this (assuming we know the input can only be a function or a class):
function isFunction(funcOrClass) {
const propertyNames = Object.getOwnPropertyNames(funcOrClass);
return (!propertyNames.includes('prototype') || propertyNames.includes('arguments'));
}
function isFunction(funcOrClass) {
const propertyNames = Object.getOwnPropertyNames(funcOrClass);
return (!propertyNames.includes('prototype') || propertyNames.includes('arguments'));
}
console.log('class isFunction?', isFunction(class A {}));
console.log('function isFunction?', isFunction(function() {}));
console.log('async function isFunction?', isFunction(async function() {}));
console.log('arrow function isFunction?', isFunction(() => {}));
Now that we have native implementations of ES6, there are "real classes". These are largely syntactic sugar for prototypal inheritance as with constructor functions, but there are subtle differences and the two are not completely interchangeable.
So far, the only way I've found is to get the .toString()
of the object's prototype's constructor function and check if it starts with class
OR if the object has a constructor and the .toString()
of that starts with class
.
Note that if your code is compiled (ie: most Babel or TypeScript setups), then this will return function...
instead of class...
at runtime (since classes are transpiled to constructor functions).
function isClass(obj) {
const isCtorClass = obj.constructor
&& obj.constructor.toString().substring(0, 5) === 'class'
if(obj.prototype === undefined) {
return isCtorClass
}
const isPrototypeCtorClass = obj.prototype.constructor
&& obj.prototype.constructor.toString
&& obj.prototype.constructor.toString().substring(0, 5) === 'class'
return isCtorClass || isPrototypeCtorClass
}
This will only work in native environments (Chrome, Firefox, Edge, node.js, etc.) that have implemented class
for code that has not been transpiled to function
.
Usage:
class A {}
class B extends A {}
isClass(A) // true
isClass(new A()) // true
isClass(B) // true
isClass(new B()) // true
function C() {}
isClass(C) // false
isClass(new C()) // false
isClass({}) // false
isClass(Date) // false
isClass(new Date()) // false
//These cases return 'true' but I'm not sure it's desired
isClass(Object.create(A)) // true
const x = {}
Object.setPrototypeOf(x, A)
isClass(x) // true
If there is a better way, I'd love to know what it is.
JavaScript does not have classes. It has functions which, when used with new
, can be used to produce object instances. Therefore, you really want to test if class2
is a function. There are numerous ways of accomplishing this; the current (1.3) implementation of isFunction() in jQuery looks like this:
isFunction: function( obj ) {
return toString.call(obj) === "[object Function]";
},
...But see here for a rundown of the different methods: Best method of testing for a function in JavaScript?
There is really no such thing as a "class" in javascript -- everything but primitives are an object. Even functions are objects.
instanceof DOES work with functions though. Check out this link.
function Car(make, model, year)
{
this.make = make;
this.model = model;
this.year = year;
}
var mycar = new Car("Honda", "Accord", 1998);
var a = mycar instanceof Car; // returns true
var b = mycar instanceof Object; // returns true