I created a JavaScript object, but how I can determine the class of that object?
I want something similar to Java's .getClass() method.
There's no exact counterpart to Java's getClass() in JavaScript. Mostly that's due to JavaScript being a prototype-based language, as opposed to Java being a class-based one.
Depending on what you need getClass() for, there are several options in JavaScript:
typeof
instanceof
obj.constructor
func.prototype, proto.isPrototypeOf
A few examples:
function Foo() {}
var foo = new Foo();
typeof Foo; // == "function"
typeof foo; // == "object"
foo instanceof Foo; // == true
foo.constructor.name; // == "Foo"
Foo.name // == "Foo"
Foo.prototype.isPrototypeOf(foo); // == true
Foo.prototype.bar = function (x) {return x+x;};
foo.bar(21); // == 42
Note: if you are compiling your code with Uglify it will change non-global class names. To prevent this, Uglify has a --mangle param that you can set to false is using gulp or grunt.
obj.constructor.name
is a reliable method in modern browsers. Function.name was officially added to the standard in ES6, making this a standards-compliant means of getting the "class" of a JavaScript object as a string. If the object is instantiated with var obj = new MyClass(), it will return "MyClass".
It will return "Number" for numbers, "Array" for arrays and "Function" for functions, etc. It generally behaves as expected. The only cases where it fails are if an object is created without a prototype, via Object.create( null ), or the object was instantiated from an anonymously-defined (unnamed) function.
Also note that if you are minifying your code, it's not safe to compare against hard-coded type strings. For example instead of checking if obj.constructor.name == "MyType", instead check obj.constructor.name == MyType.name. Or just compare the constructors themselves, however this won't work across DOM boundaries as there are different instances of the constructor function on each DOM, thus doing an object comparison on their constructors won't work.
This getNativeClass() function returns "undefined" for undefined values and "null" for null.For all other values, the CLASSNAME-part is extracted from [object CLASSNAME], which is the result of using Object.prototype.toString.call(value).
getAnyClass() behaves the same as getNativeClass(), but also supports custom constructors
function getNativeClass(obj) {
if (typeof obj === "undefined") return "undefined";
if (obj === null) return "null";
return Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
}
function getAnyClass(obj) {
if (typeof obj === "undefined") return "undefined";
if (obj === null) return "null";
return obj.constructor.name;
}
getClass("") === "String";
getClass(true) === "Boolean";
getClass(0) === "Number";
getClass([]) === "Array";
getClass({}) === "Object";
getClass(null) === "null";
getAnyClass(new (function Foo(){})) === "Foo";
getAnyClass(new class Foo{}) === "Foo";
// etc...
We can read Class's name of an instance by just doing 'instance.constructor.name' like in this example:
class Person {
type = "developer";
}
let p = new Person();
p.constructor.name // Person
To get the "pseudo class", you can get the constructor function, by
obj.constructor
assuming the constructor is set correctly when you do the inheritance -- which is by something like:
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
and these two lines, together with:
var woofie = new Dog()
will make woofie.constructor point to Dog. Note that Dog is a constructor function, and is a Function object. But you can do if (woofie.constructor === Dog) { ... }.
If you want to get the class name as a string, I found the following working well:
http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects
function getObjectClass(obj) {
if (obj && obj.constructor && obj.constructor.toString) {
var arr = obj.constructor.toString().match(
/function\s*(\w+)/);
if (arr && arr.length == 2) {
return arr[1];
}
}
return undefined;
}
It gets to the constructor function, converts it to string, and extracts the name of the constructor function.
Note that obj.constructor.name could have worked well, but it is not standard. It is on Chrome and Firefox, but not on IE, including IE 9 or IE 10 RTM.
You can get a reference to the constructor function which created the object by using the constructor property:
function MyObject(){
}
var obj = new MyObject();
obj.constructor; // MyObject
If you need to confirm the type of an object at runtime you can use the instanceof operator:
obj instanceof MyObject // true
i had a situation to work generic now and used this:
class Test {
// your class definition
}
nameByType = function(type){
return type.prototype["constructor"]["name"];
};
console.log(nameByType(Test));
thats the only way i found to get the class name by type input if you don't have a instance of an object.
(written in ES2017)
dot notation also works fine
console.log(Test.prototype.constructor.name); // returns "Test"
In keeping with its unbroken record of backwards-compatibility, ECMAScript 6, JavaScript still doesn't have a class type (though not everyone understands this). It does have a class keyword as part of its class syntax for creating prototypes—but still no thing called class. JavaScript is not now and has never been a classical OOP language. Speaking of JS in terms of class is only either misleading or a sign of not yet grokking prototypical inheritance (just keeping it real).
That means this.constructor is still a great way to get a reference to the constructor function. And this.constructor.prototype is the way to access the prototype itself. Since this isn't Java, it's not a class. It's the prototype object your instance was instantiated from. Here is an example using the ES6 syntactic sugar for creating a prototype chain:
class Foo {
get foo () {
console.info(this.constructor, this.constructor.name)
return 'foo'
}
}
class Bar extends Foo {
get foo () {
console.info('[THIS]', this.constructor, this.constructor.name, Object.getOwnPropertyNames(this.constructor.prototype))
console.info('[SUPER]', super.constructor, super.constructor.name, Object.getOwnPropertyNames(super.constructor.prototype))
return `${super.foo} + bar`
}
}
const bar = new Bar()
console.dir(bar.foo)
This is what that outputs using babel-node:
> $ babel-node ./foo.js ⬡ 6.2.0 [±master ●]
[THIS] [Function: Bar] 'Bar' [ 'constructor', 'foo' ]
[SUPER] [Function: Foo] 'Foo' [ 'constructor', 'foo' ]
[Function: Bar] 'Bar'
'foo + bar'
There you have it! In 2016, there's a class keyword in JavaScript, but still no class type. this.constructor is the best way to get the constructor function, this.constructor.prototype the best way to get access to the prototype itself.
For Javascript Classes in ES6 you can use object.constructor. In the example class below the getClass() method returns the ES6 class as you would expect:
var Cat = class {
meow() {
console.log("meow!");
}
getClass() {
return this.constructor;
}
}
var fluffy = new Cat();
...
var AlsoCat = fluffy.getClass();
var ruffles = new AlsoCat();
ruffles.meow(); // "meow!"
If you instantiate the class from the getClass method make sure you wrap it in brackets e.g. ruffles = new ( fluffy.getClass() )( args... );
If you need to not only GET class but also EXTEND it from having just an instance, write:
let's have
class A{
constructor(name){
this.name = name
}
};
const a1 = new A('hello a1');
so to extend A having the instance only use:
const a2 = new (Object.getPrototypeOf(a1)).constructor('hello from a2')
// the analog of const a2 = new A()
console.log(a2.name)//'hello from a2'
I find object.constructor.toString() return [object objectClass] in IE ,rather than function objectClass () {} returned in chome. So,I think the code in http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects may not work well in IE.And I fixed the code as follows:
code:
var getObjectClass = function (obj) {
if (obj && obj.constructor && obj.constructor.toString()) {
/*
* for browsers which have name property in the constructor
* of the object,such as chrome
*/
if(obj.constructor.name) {
return obj.constructor.name;
}
var str = obj.constructor.toString();
/*
* executed if the return of object.constructor.toString() is
* "[object objectClass]"
*/
if(str.charAt(0) == '[')
{
var arr = str.match(/\[\w+\s*(\w+)\]/);
} else {
/*
* executed if the return of object.constructor.toString() is
* "function objectClass () {}"
* for IE Firefox
*/
var arr = str.match(/function\s*(\w+)/);
}
if (arr && arr.length == 2) {
return arr[1];
}
}
return undefined;
};
In javascript, there are no classes, but I think that you want the constructor name and obj.constructor.toString() will tell you what you need.
getClass() function using constructor.prototype.name
I found a way to access the class that is much cleaner than some of the solutions above; here it is.
function getClass(obj) {
// if the type is not an object return the type
if((let type = typeof obj) !== 'object') return type;
//otherwise, access the class using obj.constructor.name
else return obj.constructor.name;
}
How it works
the constructor has a property called name accessing that will give you the class name.
cleaner version of the code:
function getClass(obj) {
// if the type is not an object return the type
let type = typeof obj
if((type !== 'object')) {
return type;
} else { //otherwise, access the class using obj.constructor.name
return obj.constructor.name;
}
}
Agree with dfa, that's why i consider the prototye as the class when no named class found
Here is an upgraded function of the one posted by Eli Grey, to match my way of mind
function what(obj){
if(typeof(obj)==="undefined")return "undefined";
if(obj===null)return "Null";
var res = Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
if(res==="Object"){
res = obj.constructor.name;
if(typeof(res)!='string' || res.length==0){
if(obj instanceof jQuery)return "jQuery";// jQuery build stranges Objects
if(obj instanceof Array)return "Array";// Array prototype is very sneaky
return "Object";
}
}
return res;
}
Here's a implementation of getClass() and getInstance()
You are able to get a reference for an Object's class using this.constructor.
From an instance context:
function A() {
this.getClass = function() {
return this.constructor;
}
this.getNewInstance = function() {
return new this.constructor;
}
}
var a = new A();
console.log(a.getClass()); // function A { // etc... }
// you can even:
var b = new (a.getClass());
console.log(b instanceof A); // true
var c = a.getNewInstance();
console.log(c instanceof A); // true
From static context:
function A() {};
A.getClass = function() {
return this;
}
A.getInstance() {
return new this;
}
Don't use o.constructor because it can be changed by the object content. Instead, use Object.getPrototypeOf()?.constructor.
const fakedArray = JSON.parse('{ "constructor": { "name": "Array" } }');
// returns 'Array', which is faked.
fakedArray.constructor.name;
// returns 'Object' as expected
Object.getPrototypeOf(fakedArray)?.constructor?.name;
I suggest using Object.prototype.constructor.name:
Object.defineProperty(Object.prototype, "getClass", {
value: function() {
return this.constructor.name;
}
});
var x = new DOMParser();
console.log(x.getClass()); // `DOMParser'
var y = new Error("");
console.log(y.getClass()); // `Error'
You can also do something like this
class Hello {
constructor(){
}
}
function isClass (func) {
return typeof func === 'function' && /^class\s/.test(Function.prototype.toString.call(func))
}
console.log(isClass(Hello))
This will tell you if the input is class or not
If you have access to an instance of the class Foo (say foo = new Foo()) then there is exactly one way to get access to the the class from the instance: foo.Contructor in Javascript = foo.getClass() in Java.
eval() is another way, but since eval() is never recommended and works for everything (analogous to Java reflection), that answer is not recommended. foo.Constructor = Foo
Javascript is a class-less languages: there are no classes that defines the behaviour of a class statically as in Java. JavaScript uses prototypes instead of classes for defining object properties, including methods, and inheritance. It is possible to simulate many class-based features with prototypes in JavaScript.
Question seems already answered but the OP wants to access the class of and object, just like we do in Java and the selected answer is not enough (imho).
With the following explanation, we can get a class of an object(it's actually called prototype in javascript).
var arr = new Array('red', 'green', 'blue');
var arr2 = new Array('white', 'black', 'orange');
You can add a property like this:
Object.defineProperty(arr,'last', {
get: function(){
return this[this.length -1];
}
});
console.log(arr.last) // blue
But .last property will only be available to 'arr' object which is instantiated from Array prototype. So, in order to have the .last property to be available for all objects instantiated from Array prototype, we have to define the .last property for Array prototype:
Object.defineProperty(Array.prototype,'last', {
get: function(){
return this[this.length -1];
}
});
console.log(arr.last) // blue
console.log(arr2.last) // orange
The problem here is, you have to know which object type (prototype) the 'arr' and 'arr2' variables belongs to! In other words, if you don't know class type (prototype) of the 'arr' object, then you won't be able to define a property for them. In the above example, we know arr is instance of the Array object, that's why we used Array.prototype to define a property for Array. But what if we didn't know the class(prototype) of the 'arr'?
Object.defineProperty(arr.__proto__,'last2', {
get: function(){
return this[this.length -1];
}
});
console.log(arr.last) // blue
console.log(arr2.last) // orange
As you can see, without knowing that 'arr' is an Array, we can add a new property just bu referring the class of the 'arr' by using 'arr.__proto__'.
We accessed the prototype of the 'arr' without knowing that it's an instance of Array and I think that's what OP asked.
There is one another technique to identify your class
You can store ref to your class in instance like below.
class MyClass {
static myStaticProperty = 'default';
constructor() {
this.__class__ = new.target;
this.showStaticProperty = function() {
console.log(this.__class__.myStaticProperty);
}
}
}
class MyChildClass extends MyClass {
static myStaticProperty = 'custom';
}
let myClass = new MyClass();
let child = new MyChildClass();
myClass.showStaticProperty(); // default
child.showStaticProperty(); // custom
myClass.__class__ === MyClass; // true
child.__class__ === MyClass; // false
child.__class__ === MyChildClass; // true
Related
I am building a json formatter application. and I am very much confused by the toString method.
let's say I have an object. I parse it into a ul li Dom tree to illustrate. and I add a label based on the variable type.
function getText(val){
v = val.toString();
let p = document.createElement('span');
p.innerText = v;
return p;
}
it works fine for common types such as string, number, etc. but, when working with user defined object:
f = new TestClass();
console.log(getText(f));
{/* <span>[object Object]</span> */}
it produced a strange result. I have read relevant posts such as Overwriting toString function, and understand how it works.
basically, I understand javascript object's toString method the same as python's dunder __str__, for example, when something like:
`${f}`
is implemented TestClass.toString is called. then I tried to see where it is defined, what is the base class it inherits from, but I got nothing. super is not allowed in this context.
for user defined object, how can I determine whether a costume toString is defined on instance or not?
something like:
class TestClass1{
}
class TestClass2{
toString(){
}
}
console.log(new TestClass1().toString === undefined)
// should return true
console.log(new TestClass2().toString === undefined)
// should return false
You can check in their prototype if the toString() is the same as Object's or not:
TestClass.prototype.toString === Object.prototype.toString
Or, via an instance:
// preferred method:
Object.getPrototypeOf(testClassInstance).toString === Object.prototype.toString
// alternative accessing __proto__ directly:
testClassInstance.__proto__.toString === Object.prototype.toString
Demo:
class TestClass {
toString() { return 'I am TestClass'; }
}
const tc = new TestClass();
class ClassWithoutToString { }
const cwts = new ClassWithoutToString();
console.log(
TestClass.prototype.toString === Object.prototype.toString,
ClassWithoutToString.prototype.toString === Object.prototype.toString
);
console.log(
Object.getPrototypeOf(tc).toString === Object.prototype.toString,
Object.getPrototypeOf(cwts).toString === Object.prototype.toString
);
I created a JavaScript object, but how I can determine the class of that object?
I want something similar to Java's .getClass() method.
There's no exact counterpart to Java's getClass() in JavaScript. Mostly that's due to JavaScript being a prototype-based language, as opposed to Java being a class-based one.
Depending on what you need getClass() for, there are several options in JavaScript:
typeof
instanceof
obj.constructor
func.prototype, proto.isPrototypeOf
A few examples:
function Foo() {}
var foo = new Foo();
typeof Foo; // == "function"
typeof foo; // == "object"
foo instanceof Foo; // == true
foo.constructor.name; // == "Foo"
Foo.name // == "Foo"
Foo.prototype.isPrototypeOf(foo); // == true
Foo.prototype.bar = function (x) {return x+x;};
foo.bar(21); // == 42
Note: if you are compiling your code with Uglify it will change non-global class names. To prevent this, Uglify has a --mangle param that you can set to false is using gulp or grunt.
obj.constructor.name
is a reliable method in modern browsers. Function.name was officially added to the standard in ES6, making this a standards-compliant means of getting the "class" of a JavaScript object as a string. If the object is instantiated with var obj = new MyClass(), it will return "MyClass".
It will return "Number" for numbers, "Array" for arrays and "Function" for functions, etc. It generally behaves as expected. The only cases where it fails are if an object is created without a prototype, via Object.create( null ), or the object was instantiated from an anonymously-defined (unnamed) function.
Also note that if you are minifying your code, it's not safe to compare against hard-coded type strings. For example instead of checking if obj.constructor.name == "MyType", instead check obj.constructor.name == MyType.name. Or just compare the constructors themselves, however this won't work across DOM boundaries as there are different instances of the constructor function on each DOM, thus doing an object comparison on their constructors won't work.
This getNativeClass() function returns "undefined" for undefined values and "null" for null.For all other values, the CLASSNAME-part is extracted from [object CLASSNAME], which is the result of using Object.prototype.toString.call(value).
getAnyClass() behaves the same as getNativeClass(), but also supports custom constructors
function getNativeClass(obj) {
if (typeof obj === "undefined") return "undefined";
if (obj === null) return "null";
return Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
}
function getAnyClass(obj) {
if (typeof obj === "undefined") return "undefined";
if (obj === null) return "null";
return obj.constructor.name;
}
getClass("") === "String";
getClass(true) === "Boolean";
getClass(0) === "Number";
getClass([]) === "Array";
getClass({}) === "Object";
getClass(null) === "null";
getAnyClass(new (function Foo(){})) === "Foo";
getAnyClass(new class Foo{}) === "Foo";
// etc...
We can read Class's name of an instance by just doing 'instance.constructor.name' like in this example:
class Person {
type = "developer";
}
let p = new Person();
p.constructor.name // Person
To get the "pseudo class", you can get the constructor function, by
obj.constructor
assuming the constructor is set correctly when you do the inheritance -- which is by something like:
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
and these two lines, together with:
var woofie = new Dog()
will make woofie.constructor point to Dog. Note that Dog is a constructor function, and is a Function object. But you can do if (woofie.constructor === Dog) { ... }.
If you want to get the class name as a string, I found the following working well:
http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects
function getObjectClass(obj) {
if (obj && obj.constructor && obj.constructor.toString) {
var arr = obj.constructor.toString().match(
/function\s*(\w+)/);
if (arr && arr.length == 2) {
return arr[1];
}
}
return undefined;
}
It gets to the constructor function, converts it to string, and extracts the name of the constructor function.
Note that obj.constructor.name could have worked well, but it is not standard. It is on Chrome and Firefox, but not on IE, including IE 9 or IE 10 RTM.
You can get a reference to the constructor function which created the object by using the constructor property:
function MyObject(){
}
var obj = new MyObject();
obj.constructor; // MyObject
If you need to confirm the type of an object at runtime you can use the instanceof operator:
obj instanceof MyObject // true
i had a situation to work generic now and used this:
class Test {
// your class definition
}
nameByType = function(type){
return type.prototype["constructor"]["name"];
};
console.log(nameByType(Test));
thats the only way i found to get the class name by type input if you don't have a instance of an object.
(written in ES2017)
dot notation also works fine
console.log(Test.prototype.constructor.name); // returns "Test"
In keeping with its unbroken record of backwards-compatibility, ECMAScript 6, JavaScript still doesn't have a class type (though not everyone understands this). It does have a class keyword as part of its class syntax for creating prototypes—but still no thing called class. JavaScript is not now and has never been a classical OOP language. Speaking of JS in terms of class is only either misleading or a sign of not yet grokking prototypical inheritance (just keeping it real).
That means this.constructor is still a great way to get a reference to the constructor function. And this.constructor.prototype is the way to access the prototype itself. Since this isn't Java, it's not a class. It's the prototype object your instance was instantiated from. Here is an example using the ES6 syntactic sugar for creating a prototype chain:
class Foo {
get foo () {
console.info(this.constructor, this.constructor.name)
return 'foo'
}
}
class Bar extends Foo {
get foo () {
console.info('[THIS]', this.constructor, this.constructor.name, Object.getOwnPropertyNames(this.constructor.prototype))
console.info('[SUPER]', super.constructor, super.constructor.name, Object.getOwnPropertyNames(super.constructor.prototype))
return `${super.foo} + bar`
}
}
const bar = new Bar()
console.dir(bar.foo)
This is what that outputs using babel-node:
> $ babel-node ./foo.js ⬡ 6.2.0 [±master ●]
[THIS] [Function: Bar] 'Bar' [ 'constructor', 'foo' ]
[SUPER] [Function: Foo] 'Foo' [ 'constructor', 'foo' ]
[Function: Bar] 'Bar'
'foo + bar'
There you have it! In 2016, there's a class keyword in JavaScript, but still no class type. this.constructor is the best way to get the constructor function, this.constructor.prototype the best way to get access to the prototype itself.
For Javascript Classes in ES6 you can use object.constructor. In the example class below the getClass() method returns the ES6 class as you would expect:
var Cat = class {
meow() {
console.log("meow!");
}
getClass() {
return this.constructor;
}
}
var fluffy = new Cat();
...
var AlsoCat = fluffy.getClass();
var ruffles = new AlsoCat();
ruffles.meow(); // "meow!"
If you instantiate the class from the getClass method make sure you wrap it in brackets e.g. ruffles = new ( fluffy.getClass() )( args... );
If you need to not only GET class but also EXTEND it from having just an instance, write:
let's have
class A{
constructor(name){
this.name = name
}
};
const a1 = new A('hello a1');
so to extend A having the instance only use:
const a2 = new (Object.getPrototypeOf(a1)).constructor('hello from a2')
// the analog of const a2 = new A()
console.log(a2.name)//'hello from a2'
I find object.constructor.toString() return [object objectClass] in IE ,rather than function objectClass () {} returned in chome. So,I think the code in http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects may not work well in IE.And I fixed the code as follows:
code:
var getObjectClass = function (obj) {
if (obj && obj.constructor && obj.constructor.toString()) {
/*
* for browsers which have name property in the constructor
* of the object,such as chrome
*/
if(obj.constructor.name) {
return obj.constructor.name;
}
var str = obj.constructor.toString();
/*
* executed if the return of object.constructor.toString() is
* "[object objectClass]"
*/
if(str.charAt(0) == '[')
{
var arr = str.match(/\[\w+\s*(\w+)\]/);
} else {
/*
* executed if the return of object.constructor.toString() is
* "function objectClass () {}"
* for IE Firefox
*/
var arr = str.match(/function\s*(\w+)/);
}
if (arr && arr.length == 2) {
return arr[1];
}
}
return undefined;
};
In javascript, there are no classes, but I think that you want the constructor name and obj.constructor.toString() will tell you what you need.
getClass() function using constructor.prototype.name
I found a way to access the class that is much cleaner than some of the solutions above; here it is.
function getClass(obj) {
// if the type is not an object return the type
if((let type = typeof obj) !== 'object') return type;
//otherwise, access the class using obj.constructor.name
else return obj.constructor.name;
}
How it works
the constructor has a property called name accessing that will give you the class name.
cleaner version of the code:
function getClass(obj) {
// if the type is not an object return the type
let type = typeof obj
if((type !== 'object')) {
return type;
} else { //otherwise, access the class using obj.constructor.name
return obj.constructor.name;
}
}
Agree with dfa, that's why i consider the prototye as the class when no named class found
Here is an upgraded function of the one posted by Eli Grey, to match my way of mind
function what(obj){
if(typeof(obj)==="undefined")return "undefined";
if(obj===null)return "Null";
var res = Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
if(res==="Object"){
res = obj.constructor.name;
if(typeof(res)!='string' || res.length==0){
if(obj instanceof jQuery)return "jQuery";// jQuery build stranges Objects
if(obj instanceof Array)return "Array";// Array prototype is very sneaky
return "Object";
}
}
return res;
}
Here's a implementation of getClass() and getInstance()
You are able to get a reference for an Object's class using this.constructor.
From an instance context:
function A() {
this.getClass = function() {
return this.constructor;
}
this.getNewInstance = function() {
return new this.constructor;
}
}
var a = new A();
console.log(a.getClass()); // function A { // etc... }
// you can even:
var b = new (a.getClass());
console.log(b instanceof A); // true
var c = a.getNewInstance();
console.log(c instanceof A); // true
From static context:
function A() {};
A.getClass = function() {
return this;
}
A.getInstance() {
return new this;
}
Don't use o.constructor because it can be changed by the object content. Instead, use Object.getPrototypeOf()?.constructor.
const fakedArray = JSON.parse('{ "constructor": { "name": "Array" } }');
// returns 'Array', which is faked.
fakedArray.constructor.name;
// returns 'Object' as expected
Object.getPrototypeOf(fakedArray)?.constructor?.name;
I suggest using Object.prototype.constructor.name:
Object.defineProperty(Object.prototype, "getClass", {
value: function() {
return this.constructor.name;
}
});
var x = new DOMParser();
console.log(x.getClass()); // `DOMParser'
var y = new Error("");
console.log(y.getClass()); // `Error'
You can also do something like this
class Hello {
constructor(){
}
}
function isClass (func) {
return typeof func === 'function' && /^class\s/.test(Function.prototype.toString.call(func))
}
console.log(isClass(Hello))
This will tell you if the input is class or not
If you have access to an instance of the class Foo (say foo = new Foo()) then there is exactly one way to get access to the the class from the instance: foo.Contructor in Javascript = foo.getClass() in Java.
eval() is another way, but since eval() is never recommended and works for everything (analogous to Java reflection), that answer is not recommended. foo.Constructor = Foo
Javascript is a class-less languages: there are no classes that defines the behaviour of a class statically as in Java. JavaScript uses prototypes instead of classes for defining object properties, including methods, and inheritance. It is possible to simulate many class-based features with prototypes in JavaScript.
Question seems already answered but the OP wants to access the class of and object, just like we do in Java and the selected answer is not enough (imho).
With the following explanation, we can get a class of an object(it's actually called prototype in javascript).
var arr = new Array('red', 'green', 'blue');
var arr2 = new Array('white', 'black', 'orange');
You can add a property like this:
Object.defineProperty(arr,'last', {
get: function(){
return this[this.length -1];
}
});
console.log(arr.last) // blue
But .last property will only be available to 'arr' object which is instantiated from Array prototype. So, in order to have the .last property to be available for all objects instantiated from Array prototype, we have to define the .last property for Array prototype:
Object.defineProperty(Array.prototype,'last', {
get: function(){
return this[this.length -1];
}
});
console.log(arr.last) // blue
console.log(arr2.last) // orange
The problem here is, you have to know which object type (prototype) the 'arr' and 'arr2' variables belongs to! In other words, if you don't know class type (prototype) of the 'arr' object, then you won't be able to define a property for them. In the above example, we know arr is instance of the Array object, that's why we used Array.prototype to define a property for Array. But what if we didn't know the class(prototype) of the 'arr'?
Object.defineProperty(arr.__proto__,'last2', {
get: function(){
return this[this.length -1];
}
});
console.log(arr.last) // blue
console.log(arr2.last) // orange
As you can see, without knowing that 'arr' is an Array, we can add a new property just bu referring the class of the 'arr' by using 'arr.__proto__'.
We accessed the prototype of the 'arr' without knowing that it's an instance of Array and I think that's what OP asked.
There is one another technique to identify your class
You can store ref to your class in instance like below.
class MyClass {
static myStaticProperty = 'default';
constructor() {
this.__class__ = new.target;
this.showStaticProperty = function() {
console.log(this.__class__.myStaticProperty);
}
}
}
class MyChildClass extends MyClass {
static myStaticProperty = 'custom';
}
let myClass = new MyClass();
let child = new MyChildClass();
myClass.showStaticProperty(); // default
child.showStaticProperty(); // custom
myClass.__class__ === MyClass; // true
child.__class__ === MyClass; // false
child.__class__ === MyChildClass; // true
I often use Crockford's prototypal pattern when writing JavaScript programs. I thought I understood all the "gotchas" involved, but I discovered one I didn't think about before. I'd like to know if anyone has a best practice for handling it.
Here's a simple example:
// Here's the parent object
var MyObject = {
registry: {},
flatAttribute: null,
create: function () {
var o, F = function () {};
F.prototype = this;
o = new F();
return o;
}
};
// instance is an empty object that inherits
// from MyObject
var instance = MyObject.create();
// Attributes can be set on instance without modifying MyObject
instance.flatAttribute = "This is going to be applied to the instance";
// registry doesn't exist on instance, but it exists on
// instance.prototype. MyObject's registry attribute gets
// dug up the prototype chain and altered. It's not possible
// to tell that's happening just by examining this line.
instance.registry.newAttribute = "This is going to be applied to the prototype";
// Inspecting the parent object
// prints "null"
console.log(MyObject.flatAttribute);
// prints "This is going to be applied to the prototype"
console.log(MyObject.registry.newAttribute);
I want to feel safe that any changes that appear to be made to the instance don't propagate up the inheritance change. This is not the case when the attribute is an object and I'm setting a nested property.
A solution is to re-initialize all object attributes on the instance. However, one of the stated advantages of using this pattern is removing re-initialization code from the constructor. I'm thinking about cloning all the object attributes of the parent and setting them on the instance within the create() function:
{ create: function () {
var o, a, F = function () {};
F.prototype = this;
o = new F();
for (a in this) {
if (this.hasOwnProperty(a) && typeof this[a] === 'object') {
// obviously deepclone would need to be implemented
o[a] = deepclone(this[a]);
}
}
return o;
} };
Is there a better way?
There is a very simple solution to ensuring that they are instance variables only, which is to use the this keyword in the constructor.
var MyObject = {
flatAttribute: null,
create: function () {
var o, F = function () {
this.registry = {}
};
F.prototype = this;
o = new F();
return o;
}
};
this ensures that all properties of "instance.registry.*" are local to the instance because the lookup order for javascript opjects is as follows.
object -> prototype -> parent prototype ...
so by adding a variable to the instance in the constructor function named "registry" that will always be found first.
another solution, which I think is more elegant is to not use crockford's (java style) constructors and use a layout that reflects javascripts object system more naturally. most of those gotchas are from the misfit between practice and language.
// instance stuff
var F = function () {
this.registry = {}
};
F.prototype = {
// static attributes here
flatAttribute: null,
methodA: function(){
// code here 'this' is instance object
this.att = 'blah';
}
};
var instanceA = new F();
instanceA.registry['A'] = 'hi';
var instanceB = new F();
instanceB.registry['B'] = 'hello';
instanceA.registry.A == 'hi'; // true
instanceB.registry.B == 'hello'; // true
F.prototype.registry == undefined; // true
Will this give you the expected result? Here I am not using an Object literal, but an instantly instantiated constructor function for the parent object (Base):
var Base = ( function(){
function MyObject(){
this.registry = {},
this.flatAttribute = null;
if (!MyObject.prototype.create)
MyObject.prototype.create = function(){
return new this.constructor();
};
}
return new MyObject;
} )(),
// create 2 instances from Base
instance1 = Base.create(),
instance2 = Base.create();
// assign a property to instance1.registry
instance1.registry.something = 'blabla';
// do the instance properties really belong to the instance?
console.log(instance1.registry.something); //=> 'blabla'
console.log(instance2.registry.something === undefined); //=> true
But it's all a bit virtual. If you don't want to use the new operator (I think that was te whole idea of it), the following offers you a way to do that without the need for a create method :
function Base2(){
if (!(this instanceof Base2)){
return new Base2;
}
this.registry = {},
this.flatAttribute = null;
if (!Base2.prototype.someMethod){
var proto = Base2.prototype;
proto.someMethod = function(){};
//...etc
}
}
//now the following does the same as before:
var instance1 = Base2(),
instance2 = Base2();
// assign a property to instance1.registry
instance1.registry.something = 'blabla';
// do the instance properties really belong to the instance?
console.log(instance1.registry.something); //=> 'blabla'
console.log(instance2.registry.something === undefined); //=> true
Example in a jsfiddle
I always like to keep in mind that object.Create is one option, and not the only way of achieving non-classical inheritance in javascript.
For myself, I always find that Object.create works best when I want to inherit elements from the parent objects prototype chain (i.e. methods that I'd like to be able to apply to the inheriting object).
--
For simple "Own Property" inheritance, Object.create is largely unnecessary. When I want to inherit own properties, i prefer to use the popular Mixin & Extend patterns (which simply copy one object's own properties to another, without worrying about prototype or "new").
In the Stoyan Stefanov book "Javascript Patterns" he gives an example of a deep extend function that does what you're looking for recursively, and includes support for properties that are arrays as well as standard key/value objects:
function extendDeep(parent, child){
var i,
toStr = Object.prototype.toString,
astr = "[object Array]";
child = child || {};
for (i in parent) {
if (parent.hasOwnProperty(i)) {
if (typeof parent[i] === "object") {
child[i] = (toStr.call(parent[i]) === astr) ? [] : {};
extendDeep(parent[i], child[i]);
} else {
child[i] = parent[i];
}
}
}
return child;
}
If you're using jQuery, jQuery.extend() has an optional "deep" argument that lets you extend an object in near-identical fashion.
i think you're using prototypal inheritance to simulate a classic, Object Oriented inheritance.
What are you trying to do is to stop the prototype method lookup which limits its expressiveness, so why using it? You can achieve the same effect by using this functional pattern:
var MyObject = function() {
// Declare here shared vars
var global = "All instances shares me!";
return {
'create': function() {
var flatAttribute;
var register = {};
return {
// Declare here public getters/setters
'register': (function() {
return register;
})(),
'flatAttribute': (function() {
return flatAttribute;
})(),
'global': (function() {
return global;
})()
};
}
};
}();
var instance1 = MyObject.create();
var instance2 = MyObject.create();
instance1.register.newAttr = "This is local to instance1";
instance2.register.newAttr = "This is local to instance2";
// Print local (instance) var
console.log(instance1.register.newAttr);
console.log(instance2.register.newAttr);
// Print global var
console.log(instance1.global);
console.log(instance2.global);
Code on jsFiddle
I created a JavaScript object, but how I can determine the class of that object?
I want something similar to Java's .getClass() method.
There's no exact counterpart to Java's getClass() in JavaScript. Mostly that's due to JavaScript being a prototype-based language, as opposed to Java being a class-based one.
Depending on what you need getClass() for, there are several options in JavaScript:
typeof
instanceof
obj.constructor
func.prototype, proto.isPrototypeOf
A few examples:
function Foo() {}
var foo = new Foo();
typeof Foo; // == "function"
typeof foo; // == "object"
foo instanceof Foo; // == true
foo.constructor.name; // == "Foo"
Foo.name // == "Foo"
Foo.prototype.isPrototypeOf(foo); // == true
Foo.prototype.bar = function (x) {return x+x;};
foo.bar(21); // == 42
Note: if you are compiling your code with Uglify it will change non-global class names. To prevent this, Uglify has a --mangle param that you can set to false is using gulp or grunt.
obj.constructor.name
is a reliable method in modern browsers. Function.name was officially added to the standard in ES6, making this a standards-compliant means of getting the "class" of a JavaScript object as a string. If the object is instantiated with var obj = new MyClass(), it will return "MyClass".
It will return "Number" for numbers, "Array" for arrays and "Function" for functions, etc. It generally behaves as expected. The only cases where it fails are if an object is created without a prototype, via Object.create( null ), or the object was instantiated from an anonymously-defined (unnamed) function.
Also note that if you are minifying your code, it's not safe to compare against hard-coded type strings. For example instead of checking if obj.constructor.name == "MyType", instead check obj.constructor.name == MyType.name. Or just compare the constructors themselves, however this won't work across DOM boundaries as there are different instances of the constructor function on each DOM, thus doing an object comparison on their constructors won't work.
This getNativeClass() function returns "undefined" for undefined values and "null" for null.For all other values, the CLASSNAME-part is extracted from [object CLASSNAME], which is the result of using Object.prototype.toString.call(value).
getAnyClass() behaves the same as getNativeClass(), but also supports custom constructors
function getNativeClass(obj) {
if (typeof obj === "undefined") return "undefined";
if (obj === null) return "null";
return Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
}
function getAnyClass(obj) {
if (typeof obj === "undefined") return "undefined";
if (obj === null) return "null";
return obj.constructor.name;
}
getClass("") === "String";
getClass(true) === "Boolean";
getClass(0) === "Number";
getClass([]) === "Array";
getClass({}) === "Object";
getClass(null) === "null";
getAnyClass(new (function Foo(){})) === "Foo";
getAnyClass(new class Foo{}) === "Foo";
// etc...
We can read Class's name of an instance by just doing 'instance.constructor.name' like in this example:
class Person {
type = "developer";
}
let p = new Person();
p.constructor.name // Person
To get the "pseudo class", you can get the constructor function, by
obj.constructor
assuming the constructor is set correctly when you do the inheritance -- which is by something like:
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
and these two lines, together with:
var woofie = new Dog()
will make woofie.constructor point to Dog. Note that Dog is a constructor function, and is a Function object. But you can do if (woofie.constructor === Dog) { ... }.
If you want to get the class name as a string, I found the following working well:
http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects
function getObjectClass(obj) {
if (obj && obj.constructor && obj.constructor.toString) {
var arr = obj.constructor.toString().match(
/function\s*(\w+)/);
if (arr && arr.length == 2) {
return arr[1];
}
}
return undefined;
}
It gets to the constructor function, converts it to string, and extracts the name of the constructor function.
Note that obj.constructor.name could have worked well, but it is not standard. It is on Chrome and Firefox, but not on IE, including IE 9 or IE 10 RTM.
You can get a reference to the constructor function which created the object by using the constructor property:
function MyObject(){
}
var obj = new MyObject();
obj.constructor; // MyObject
If you need to confirm the type of an object at runtime you can use the instanceof operator:
obj instanceof MyObject // true
i had a situation to work generic now and used this:
class Test {
// your class definition
}
nameByType = function(type){
return type.prototype["constructor"]["name"];
};
console.log(nameByType(Test));
thats the only way i found to get the class name by type input if you don't have a instance of an object.
(written in ES2017)
dot notation also works fine
console.log(Test.prototype.constructor.name); // returns "Test"
In keeping with its unbroken record of backwards-compatibility, ECMAScript 6, JavaScript still doesn't have a class type (though not everyone understands this). It does have a class keyword as part of its class syntax for creating prototypes—but still no thing called class. JavaScript is not now and has never been a classical OOP language. Speaking of JS in terms of class is only either misleading or a sign of not yet grokking prototypical inheritance (just keeping it real).
That means this.constructor is still a great way to get a reference to the constructor function. And this.constructor.prototype is the way to access the prototype itself. Since this isn't Java, it's not a class. It's the prototype object your instance was instantiated from. Here is an example using the ES6 syntactic sugar for creating a prototype chain:
class Foo {
get foo () {
console.info(this.constructor, this.constructor.name)
return 'foo'
}
}
class Bar extends Foo {
get foo () {
console.info('[THIS]', this.constructor, this.constructor.name, Object.getOwnPropertyNames(this.constructor.prototype))
console.info('[SUPER]', super.constructor, super.constructor.name, Object.getOwnPropertyNames(super.constructor.prototype))
return `${super.foo} + bar`
}
}
const bar = new Bar()
console.dir(bar.foo)
This is what that outputs using babel-node:
> $ babel-node ./foo.js ⬡ 6.2.0 [±master ●]
[THIS] [Function: Bar] 'Bar' [ 'constructor', 'foo' ]
[SUPER] [Function: Foo] 'Foo' [ 'constructor', 'foo' ]
[Function: Bar] 'Bar'
'foo + bar'
There you have it! In 2016, there's a class keyword in JavaScript, but still no class type. this.constructor is the best way to get the constructor function, this.constructor.prototype the best way to get access to the prototype itself.
For Javascript Classes in ES6 you can use object.constructor. In the example class below the getClass() method returns the ES6 class as you would expect:
var Cat = class {
meow() {
console.log("meow!");
}
getClass() {
return this.constructor;
}
}
var fluffy = new Cat();
...
var AlsoCat = fluffy.getClass();
var ruffles = new AlsoCat();
ruffles.meow(); // "meow!"
If you instantiate the class from the getClass method make sure you wrap it in brackets e.g. ruffles = new ( fluffy.getClass() )( args... );
If you need to not only GET class but also EXTEND it from having just an instance, write:
let's have
class A{
constructor(name){
this.name = name
}
};
const a1 = new A('hello a1');
so to extend A having the instance only use:
const a2 = new (Object.getPrototypeOf(a1)).constructor('hello from a2')
// the analog of const a2 = new A()
console.log(a2.name)//'hello from a2'
I find object.constructor.toString() return [object objectClass] in IE ,rather than function objectClass () {} returned in chome. So,I think the code in http://blog.magnetiq.com/post/514962277/finding-out-class-names-of-javascript-objects may not work well in IE.And I fixed the code as follows:
code:
var getObjectClass = function (obj) {
if (obj && obj.constructor && obj.constructor.toString()) {
/*
* for browsers which have name property in the constructor
* of the object,such as chrome
*/
if(obj.constructor.name) {
return obj.constructor.name;
}
var str = obj.constructor.toString();
/*
* executed if the return of object.constructor.toString() is
* "[object objectClass]"
*/
if(str.charAt(0) == '[')
{
var arr = str.match(/\[\w+\s*(\w+)\]/);
} else {
/*
* executed if the return of object.constructor.toString() is
* "function objectClass () {}"
* for IE Firefox
*/
var arr = str.match(/function\s*(\w+)/);
}
if (arr && arr.length == 2) {
return arr[1];
}
}
return undefined;
};
In javascript, there are no classes, but I think that you want the constructor name and obj.constructor.toString() will tell you what you need.
getClass() function using constructor.prototype.name
I found a way to access the class that is much cleaner than some of the solutions above; here it is.
function getClass(obj) {
// if the type is not an object return the type
if((let type = typeof obj) !== 'object') return type;
//otherwise, access the class using obj.constructor.name
else return obj.constructor.name;
}
How it works
the constructor has a property called name accessing that will give you the class name.
cleaner version of the code:
function getClass(obj) {
// if the type is not an object return the type
let type = typeof obj
if((type !== 'object')) {
return type;
} else { //otherwise, access the class using obj.constructor.name
return obj.constructor.name;
}
}
Agree with dfa, that's why i consider the prototye as the class when no named class found
Here is an upgraded function of the one posted by Eli Grey, to match my way of mind
function what(obj){
if(typeof(obj)==="undefined")return "undefined";
if(obj===null)return "Null";
var res = Object.prototype.toString.call(obj).match(/^\[object\s(.*)\]$/)[1];
if(res==="Object"){
res = obj.constructor.name;
if(typeof(res)!='string' || res.length==0){
if(obj instanceof jQuery)return "jQuery";// jQuery build stranges Objects
if(obj instanceof Array)return "Array";// Array prototype is very sneaky
return "Object";
}
}
return res;
}
Here's a implementation of getClass() and getInstance()
You are able to get a reference for an Object's class using this.constructor.
From an instance context:
function A() {
this.getClass = function() {
return this.constructor;
}
this.getNewInstance = function() {
return new this.constructor;
}
}
var a = new A();
console.log(a.getClass()); // function A { // etc... }
// you can even:
var b = new (a.getClass());
console.log(b instanceof A); // true
var c = a.getNewInstance();
console.log(c instanceof A); // true
From static context:
function A() {};
A.getClass = function() {
return this;
}
A.getInstance() {
return new this;
}
Don't use o.constructor because it can be changed by the object content. Instead, use Object.getPrototypeOf()?.constructor.
const fakedArray = JSON.parse('{ "constructor": { "name": "Array" } }');
// returns 'Array', which is faked.
fakedArray.constructor.name;
// returns 'Object' as expected
Object.getPrototypeOf(fakedArray)?.constructor?.name;
I suggest using Object.prototype.constructor.name:
Object.defineProperty(Object.prototype, "getClass", {
value: function() {
return this.constructor.name;
}
});
var x = new DOMParser();
console.log(x.getClass()); // `DOMParser'
var y = new Error("");
console.log(y.getClass()); // `Error'
You can also do something like this
class Hello {
constructor(){
}
}
function isClass (func) {
return typeof func === 'function' && /^class\s/.test(Function.prototype.toString.call(func))
}
console.log(isClass(Hello))
This will tell you if the input is class or not
If you have access to an instance of the class Foo (say foo = new Foo()) then there is exactly one way to get access to the the class from the instance: foo.Contructor in Javascript = foo.getClass() in Java.
eval() is another way, but since eval() is never recommended and works for everything (analogous to Java reflection), that answer is not recommended. foo.Constructor = Foo
Javascript is a class-less languages: there are no classes that defines the behaviour of a class statically as in Java. JavaScript uses prototypes instead of classes for defining object properties, including methods, and inheritance. It is possible to simulate many class-based features with prototypes in JavaScript.
Question seems already answered but the OP wants to access the class of and object, just like we do in Java and the selected answer is not enough (imho).
With the following explanation, we can get a class of an object(it's actually called prototype in javascript).
var arr = new Array('red', 'green', 'blue');
var arr2 = new Array('white', 'black', 'orange');
You can add a property like this:
Object.defineProperty(arr,'last', {
get: function(){
return this[this.length -1];
}
});
console.log(arr.last) // blue
But .last property will only be available to 'arr' object which is instantiated from Array prototype. So, in order to have the .last property to be available for all objects instantiated from Array prototype, we have to define the .last property for Array prototype:
Object.defineProperty(Array.prototype,'last', {
get: function(){
return this[this.length -1];
}
});
console.log(arr.last) // blue
console.log(arr2.last) // orange
The problem here is, you have to know which object type (prototype) the 'arr' and 'arr2' variables belongs to! In other words, if you don't know class type (prototype) of the 'arr' object, then you won't be able to define a property for them. In the above example, we know arr is instance of the Array object, that's why we used Array.prototype to define a property for Array. But what if we didn't know the class(prototype) of the 'arr'?
Object.defineProperty(arr.__proto__,'last2', {
get: function(){
return this[this.length -1];
}
});
console.log(arr.last) // blue
console.log(arr2.last) // orange
As you can see, without knowing that 'arr' is an Array, we can add a new property just bu referring the class of the 'arr' by using 'arr.__proto__'.
We accessed the prototype of the 'arr' without knowing that it's an instance of Array and I think that's what OP asked.
There is one another technique to identify your class
You can store ref to your class in instance like below.
class MyClass {
static myStaticProperty = 'default';
constructor() {
this.__class__ = new.target;
this.showStaticProperty = function() {
console.log(this.__class__.myStaticProperty);
}
}
}
class MyChildClass extends MyClass {
static myStaticProperty = 'custom';
}
let myClass = new MyClass();
let child = new MyChildClass();
myClass.showStaticProperty(); // default
child.showStaticProperty(); // custom
myClass.__class__ === MyClass; // true
child.__class__ === MyClass; // false
child.__class__ === MyChildClass; // true
Hey all, I am trying to test if the argument passed into my function is a class name so that I may compare it to other classes using instanceof.
For example:
function foo(class1, class2) {
// Test to see if the parameter is a class.
if(class1 is a class)
{
//do some kind of class comparison.
if(class2 is a class)
{
if(class1 instanceof class2)
{
//...
}
}
else
{
//...
}
}
else
//...
}
Is this possible? I am having trouble googleing an answer.
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
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.
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(() => {}));
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?
My solution is by checking if the function prototype has property other than constructor and checking if the function prototype is Function.prototype.
This solution can also work even after transpiled with babel, or the script is running with "use strict". But this solution will only work if the class have at least one public function, or have extend other class.
function isClass(func){
// Class constructor is also a function
if(!(func && func.constructor === Function) || func.prototype === undefined)
return false;
// This is a class that extends other class
if(Function.prototype !== Object.getPrototypeOf(func))
return true;
// Usually a function will only have 'constructor' in the prototype
return Object.getOwnPropertyNames(func.prototype).length > 1;
}
// ----Example----
class Fruit{
hello(){} // At least must have one public function
}
// Or at least it extend other class
class Pear extends Fruit{}
console.log(isClass(Fruit)); // true
console.log(isClass(Pear)); // true
console.log(isClass(function(){})); // false
console.log(isClass(function(){"use strict"})); // false
console.log(isClass(() => {})); // false
console.log(isClass({hello: 1})); // false
I know that using constructor.name on a function will return "Function" but doing so on an ES6 class instance will return the name of the class.
I do use it like this:
function isAClassInstance(item){
return item.constructor.name !== "Function" && item.constructor.name !== "Object";
}
class A {};
function B(){};
const aInstanceClass = new A();
const bFunctionInstance = new B();
const bFunction = B;
const aClass = A;
console.log(aInstanceClass.constructor.name); /*Will return "A"*/
console.log(bFunctionInstance.constructor.name); /*Will return "B"*/
console.log(A.constructor.name); /*Will return "Function"*/
console.log(B.constructor.name); /*Will return "Function"*/
console.log(bFunction.constructor.name); /*Will return "Function"*/
console.log("is A a class instance: ", isAClassInstance(aClass)); /*false*/
console.log("is B a class instance: ", isAClassInstance(aClass)); /*false*/
console.log("is aInstanceClass a class: ", isAClassInstance(aInstanceClass)); /*true*/
console.log("is bFunction a class: ", isAClassInstance(bFunction)); /*false*/
console.log("is bFunctionInstance a class: ", isAClassInstance(bFunctionInstance)); /*true*/
For the cases i used this worked perfectly.
note: since a class is technically a function doing new A() and new B() are both the same thus returning the same result from isAClassInstance.
The only way to dinstinguish a function from a class is to not use new on a function and keep this keyword for class only.
Hope this will help :).
Try this one:
function isClass(C) {
return typeof C === "function" && C.prototype !== undefined;
}
Every class is internally just a function that creates instances of this class, plus a prototype property that's assigned to [[Prototype]] of newly created objects to make them behave like instances of this particular class. So, to check if C is a class, you need to check these two things - this is what the isClass() code above does.
Note that all functions declared with function keyword can also be used with new as constructors, and inside instanceof tests. They're equivalent to classes, and have a prototype likewise, so every function of this type is (correctly) recognized as a class by the isClass() function above.
console.log(isClass(Object)); // true
console.log(isClass(Number)); // true
console.log(isClass({a:1})); // false
console.log(isClass(123)); // false
console.log(isClass("123")); // false
class A {}
class B extends A {}
console.log(isClass(A)); // true
console.log(isClass(B)); // true
console.log(isClass(new B())); // false
function f(name) { this.name = name; }
console.log(isClass(f)); // true
Hey just updating an old thread I took one of the above answers and made it work with all the predefined classes in javascript. eg. String, Map, extra
Original:
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
}
New:
export const isClass = (obj) => {
if (obj == null || typeof obj == "undefined") { return false; }
const isCtorClass = obj.constructor
&& obj.constructor.toString().substring(0, 5) === 'class'
const isNativeCtorClass= obj.constructor &&
obj.constructor.name != "Function" &&
obj.constructor.name in global;
if (obj.prototype === undefined) {
return isCtorClass || isNativeCtorClass
}
const isPrototypeCtorClass = obj.prototype.constructor
&& obj.prototype.constructor.toString
&& obj.prototype.constructor.toString().substring(0, 5) === 'class'
const isNativePrototypeCtorClass = obj.prototype.constructor.name in global && (
global[obj.prototype.constructor.name] == obj.constructor ||
global[obj.prototype.constructor.name] == obj
);
return isCtorClass || isPrototypeCtorClass || isNativeCtorClass || isNativePrototypeCtorClass
}
This checks the object in the global javascript object to check if it's a currently registered object.
Let me know if this would break for some use cases but it works for me.
isClass(function test() {}) // false
isClass(() => {}) // false
isClass(function String() {}) // false
isClass(String) // true
isClass("") // true
isClass(0) // true
isClass(class Test {}) // true
isClass(new Number(0)) // true
isClass(new (class Test{})()) // true
After reviewing the answers here I built out my own internal solution. I wanted to ensure that it only returns true if its a Class and not an instance of a class and I wanted distinguish between ES6 and classic / builtin (eg. Array) classes.
This solution should work for anything you throw at it. Please let me know if you find any exceptions.
// Will only return true for ES6 Class definitions
function isES6Class(o) {
return isClass(o, {es6: true})
}
// Will return any class unless {es6:true} is passed (see isES6Class)
function isClass(o, opts) {
if(!o)return false
if(!o.prototype) return false
if(__cls(o.constructor) || __cls(o.prototype.constructor)) return true
if(opts && opts.es6) return false
// Old school or builtin class
// If is function that has name with first letter capitalized
if((typeof o) === 'function'){
var s = funcName(o)
if (s.length > 0){
var i = s.charCodeAt(0)
if (i > 64 && i < 91){ return true }
}
}
return false
function __cls(v){
return v.toString && v.toString().indexOf('class')===0
}
}
// helper
var RE_FUNC_DEF = new RegExp("^\\s*function\\s*(\\S*)\\s*\\((.*)\\)");
function funcName(f){
if (!f) return("(funcName() - f is Nothing!)")
if(!_.isFunction(f))return("(funcName() - f is not a function!) - f = " + String(f))
var s = f.toString(), m = s.match(RE_FUNC_DEF)
if (m && m.length > 1) return m[1]
return null
}
I haven't found any 100% certain way to figure out
if something is a class and not a function. The
accepted answer above works in most cases but if
someone redefines the method toString() of their
class it may break in that case. Why would they
ever redefine toString()? I don't know, ask them
if they are still around :-)
So instead I took the approach of defining this
function:
function isClass(v)
{ if (typeof v !== "function")
{ return false;
}
if ( typeof v.isClass === "function" &&
v.isClass()
)
{ return true;
}
}
This means I can mark my own classes as
being classes I recognize as classes by
giving them the static method isClass()
which returns true. If such classes have
subclasses the subclasses inherit the
method and are thus automatically recognized
as "classes" as well.
If I need to work with someone else's
classes which does not have this method
I might first subclass their class so
that my subclass is like their class
except it also has the isClass() -method.
I hope the next version of EcmaScript will
remedy this lack of standardized solution
but for now this is the best I can do.
It has the additional benefit that I might
in fact give the method isClass() to some
of my non-class-functions as well, which are
not classes proper, and then be able to
treat such functions as if they were classes,
for whatever reason I might want to.