Is there any way to determine in Javascript if an object was created using object-literal notation or using a constructor method?
It seems to me that you just access it's parent object, but if the object you are passing in doesn't have a reference to it's parent, I don't think you can tell this, can you?
What you want is:
Object.getPrototypeOf(obj) === Object.prototype
This checks that the object is a plain object created with either new Object() or {...} and not some subclass of Object.
I just came across this question and thread during a sweet hackfest that involved a grail quest for evaluating whether an object was created with {} or new Object() (i still havent figured that out.)
Anyway, I was suprised to find the similarity between the isObjectLiteral() function posted here and my own isObjLiteral() function that I wrote for the Pollen.JS project. I believe this solution was posted prior to my Pollen.JS commit, so - hats off to you! The upside to mine is the length... less then half (when included your set up routine), but both produce the same results.
Take a look:
function isObjLiteral(_obj) {
var _test = _obj;
return ( typeof _obj !== 'object' || _obj === null ?
false :
(
(function () {
while (!false) {
if ( Object.getPrototypeOf( _test = Object.getPrototypeOf(_test) ) === null) {
break;
}
}
return Object.getPrototypeOf(_obj) === _test;
})()
)
);
}
Additionally, some test stuff:
var _cases= {
_objLit : {},
_objNew : new Object(),
_function : new Function(),
_array : new Array(),
_string : new String(),
_image : new Image(),
_bool: true
};
console.dir(_cases);
for ( var _test in _cases ) {
console.group(_test);
console.dir( {
type: typeof _cases[_test],
string: _cases[_test].toString(),
result: isObjLiteral(_cases[_test])
});
console.groupEnd();
}
Or on jsbin.com...
http://jsbin.com/iwuwa
Be sure to open firebug when you get there - debugging to the document is for IE lovers.
Edit: I'm interpreting "object literal" as anything created using an object literal or the Object constructor. This is what John Resig most likely meant.
I have a function that will work even if .constructor has been tainted or if the object was created in another frame. Note that Object.prototype.toString.call(obj) === "[object Object]" (as some may believe) will not solve this problem.
function isObjectLiteral(obj) {
if (typeof obj !== "object" || obj === null)
return false;
var hasOwnProp = Object.prototype.hasOwnProperty,
ObjProto = obj;
// get obj's Object constructor's prototype
while (Object.getPrototypeOf(ObjProto = Object.getPrototypeOf(ObjProto)) !== null);
if (!Object.getPrototypeOf.isNative) // workaround if non-native Object.getPrototypeOf
for (var prop in obj)
if (!hasOwnProp.call(obj, prop) && !hasOwnProp.call(ObjProto, prop)) // inherited elsewhere
return false;
return Object.getPrototypeOf(obj) === ObjProto;
};
if (!Object.getPrototypeOf) {
if (typeof ({}).__proto__ === "object") {
Object.getPrototypeOf = function (obj) {
return obj.__proto__;
};
Object.getPrototypeOf.isNative = true;
} else {
Object.getPrototypeOf = function (obj) {
var constructor = obj.constructor,
oldConstructor;
if (Object.prototype.hasOwnProperty.call(obj, "constructor")) {
oldConstructor = constructor;
if (!(delete obj.constructor)) // reset constructor
return null; // can't delete obj.constructor, return null
constructor = obj.constructor; // get real constructor
obj.constructor = oldConstructor; // restore constructor
}
return constructor ? constructor.prototype : null; // needed for IE
};
Object.getPrototypeOf.isNative = false;
}
} else Object.getPrototypeOf.isNative = true;
Here is the HTML for the testcase:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<!-- Online here: http://code.eligrey.com/testcases/all/isObjectLiteral.html -->
<title>isObjectLiteral</title>
<style type="text/css">
li { background: green; } li.FAIL { background: red; }
iframe { display: none; }
</style>
</head>
<body>
<ul id="results"></ul>
<script type="text/javascript">
function isObjectLiteral(obj) {
if (typeof obj !== "object" || obj === null)
return false;
var hasOwnProp = Object.prototype.hasOwnProperty,
ObjProto = obj;
// get obj's Object constructor's prototype
while (Object.getPrototypeOf(ObjProto = Object.getPrototypeOf(ObjProto)) !== null);
if (!Object.getPrototypeOf.isNative) // workaround if non-native Object.getPrototypeOf
for (var prop in obj)
if (!hasOwnProp.call(obj, prop) && !hasOwnProp.call(ObjProto, prop)) // inherited elsewhere
return false;
return Object.getPrototypeOf(obj) === ObjProto;
};
if (!Object.getPrototypeOf) {
if (typeof ({}).__proto__ === "object") {
Object.getPrototypeOf = function (obj) {
return obj.__proto__;
};
Object.getPrototypeOf.isNative = true;
} else {
Object.getPrototypeOf = function (obj) {
var constructor = obj.constructor,
oldConstructor;
if (Object.prototype.hasOwnProperty.call(obj, "constructor")) {
oldConstructor = constructor;
if (!(delete obj.constructor)) // reset constructor
return null; // can't delete obj.constructor, return null
constructor = obj.constructor; // get real constructor
obj.constructor = oldConstructor; // restore constructor
}
return constructor ? constructor.prototype : null; // needed for IE
};
Object.getPrototypeOf.isNative = false;
}
} else Object.getPrototypeOf.isNative = true;
// Function serialization is not permitted
// Does not work across all browsers
Function.prototype.toString = function(){};
// The use case that we want to match
log("{}", {}, true);
// Instantiated objects shouldn't be matched
log("new Date", new Date, false);
var fn = function(){};
// Makes the function a little more realistic
// (and harder to detect, incidentally)
fn.prototype = {someMethod: function(){}};
// Functions shouldn't be matched
log("fn", fn, false);
// Again, instantiated objects shouldn't be matched
log("new fn", new fn, false);
var fn2 = function(){};
log("new fn2", new fn2, false);
var fn3 = function(){};
fn3.prototype = {}; // impossible to detect (?) without native Object.getPrototypeOf
log("new fn3 (only passes with native Object.getPrototypeOf)", new fn3, false);
log("null", null, false);
log("undefined", undefined, false);
/* Note:
* The restriction against instantiated functions is
* due to the fact that this method will be used for
* deep-cloning an object. Instantiated objects will
* just have their reference copied over, whereas
* plain objects will need to be completely cloned.
*/
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
var doc = iframe.contentDocument || iframe.contentWindow.document;
doc.open();
doc.write("<body onload='window.top.iframeDone(Object);'>");
doc.close();
function iframeDone(otherObject){
// Objects from other windows should be matched
log("new otherObject", new otherObject, true);
}
function log(msg, a, b) {
var pass = isObjectLiteral(a) === b ? "PASS" : "FAIL";
document.getElementById("results").innerHTML +=
"<li class='" + pass + "'>" + msg + "</li>";
}
</script>
</body>
</html>
It sounds like you are looking for this:
function Foo() {}
var a = {};
var b = new Foo();
console.log(a.constructor == Object); // true
console.log(b.constructor == Object); // false
The constructor property on an object is a pointer to the function that is used to construct it. In the example above b.constructor == Foo. If the object was created using curly brackets (the array literal notation) or using new Object() then its constructor property will == Object.
Update: crescentfresh pointed out that $(document).constructor == Object rather than being equal to the jQuery constructor, so I did a little more digging. It seems that by using an object literal as the prototype of an object you render the constructor property almost worthless:
function Foo() {}
var obj = new Foo();
obj.constructor == Object; // false
but:
function Foo() {}
Foo.prototype = { objectLiteral: true };
var obj = new Foo();
obj.constructor == Object; // true
There is a very good explanation of this in another answer here, and a more involved explanation here.
I think the other answers are correct and there is not really a way to detect this.
An object literal is the notation you use to define an object - which in javascript is always in the form of a name-value pair surrounded by the curly brackets. Once this has been executed there is no way to tell if the object was created by this notation or not (actually, I think that might be an over-simplification, but basically correct). You just have an object. This is one of the great things about js in that there are a lot of short cuts to do things that might be a lot longer to write. In short, the literal notation replaces having to write:
var myobject = new Object();
I had the same issue, so I decide to go this way:
function isPlainObject(val) {
return val ? val.constructor === {}.constructor : false;
}
// Examples:
isPlainObject({}); // true
isPlainObject([]); // false
isPlainObject(new Human("Erik", 25)); // false
isPlainObject(new Date); // false
isPlainObject(new RegExp); // false
//and so on...
There is no way to tell the difference between an object built from an object literal, and one built from other means.
It's a bit like asking if you can determine whether a numeric variable was constructed by assigning the value '2' or '3-1';
If you need to do this, you'd have to put some specific signature into your object literal to detect later.
Nowaday there is a more elegant solution that respond exactly to your question:
function isObject(value) {
return value !== null && value !== undefined && Object.is(value.constructor, Object)
}
// Test stuff below //
class MyClass extends Object {
constructor(args) {
super(args)
}
say() {
console.log('hello')
}
}
function MyProto() {
Object.call(this)
}
MyProto.prototype = Object.assign(Object.create(Object.prototype), {
constructor: MyProto,
say: function() {
console.log('hello')
}
});
const testsCases = {
objectLiteral: {},
objectFromNew: new Object(),
null: null,
undefined: undefined,
number: 123,
function: new Function(),
array: new Array([1, 2, 3]),
string: new String('foobar'),
image: new Image(),
bool: true,
error: new Error('oups'),
myClass: new MyClass(),
myProto: new MyProto()
}
for (const [key, value] of Object.entries(testsCases)) {
console.log(`${key.padEnd(15)} => ${isObject(value)}`)
}
Best regards
typeof obj === 'object' && obj !== null && Object.getPrototypeOf(obj) === Object.prototype
below all return false
123
null
undefined
'abc'
false
true
[]
new Number()
new Boolean()
() => {}
function () {}
an improvement over jesse's answer
11 year old question here is my tidy solution, open to edge case suggestions;
steps -> look for objects only then compare to check properties -> object literals do not have length, prototype and for edge case stringyfy properties.
tried in test for JSON and
Object.create(Object.create({cool: "joes"})).
"use strict"
let isObjectL = a => {
if (typeof a !=='object' || ['Number','String','Boolean', 'Symbol'].includes(a.constructor.name)) return false;
let props = Object.getOwnPropertyNames(a);
if ( !props.includes('length') && !props.includes('prototype') || !props.includes('stringify')) return true;
};
let A={type:"Fiat", model:"500", color:"white"};
let B= new Object();
let C = { "name":"John", "age":30, "city":"New York"};
let D= '{ "name":"John", "age":30, "city":"New York"}';
let E = JSON.parse(D);
let F = new Boolean();
let G = new Number();
console.log(isObjectL(A));
console.log(isObjectL(B));
console.log(isObjectL(C));
console.log(isObjectL(D));
console.log(isObjectL(E));
console.log(isObjectL(JSON));
console.log(isObjectL(F));
console.log(isObjectL(G));
console.log(isObjectL(
Object.create(Object.create({cool: "joes"}))));
console.log(isObjectL());
Another variant showing inner working
isObject=function(a) {
let exclude = ['Number','String','Boolean', 'Symbol'];
let types = typeof a;
let props = Object.getOwnPropertyNames(a);
console.log((types ==='object' && !exclude.includes(a.constructor.name) &&
( !props.includes('length') && !props.includes('prototype') && !props.includes('stringify'))));
return `type: ${types} props: ${props}
----------------`}
A={type:"Fiat", model:"500", color:"white"};
B= new Object();
C = { "name":"John", "age":30, "city":"New York"};
D= '{ "name":"John", "age":30, "city":"New York"}';
E = JSON.parse(D);
F = new Boolean();
G = new Number();
console.log(isObject(A));
console.log(isObject(B));
console.log(isObject(C));
console.log(isObject(D));
console.log(isObject(E));
console.log(isObject(JSON));
console.log(isObject(F));
console.log(isObject(G));
console.log(isObject(
Object.create(Object.create({cool: "joes"}))));
Related
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 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 ran into a problem using instanceof in JavaScript:
var MyObject = function() {
var prop = {};
return prop;
}
var testObject = new MyObject();
console.log(testObject instanceof MyObject); // return false;
Instanceof returns Object instead of the expected MyObject. I can't remove "return prop"; How can I get the type MyObject for testObject ?
Thanks for helping
EDIT: Even if my question looks like this one: What's wrong with a JavaScript class whose constructor returns a function or an object, mine needed a bit more explanation about what a new does.
You could probably break it into steps based on what the new operator does
var MyObject = function () {
var prop = {};
return prop;
}
var testObject = Object.create(MyObject.prototype);
var result = MyObject.call(testObject);
// result is the actual output of new MyObject();
result = result && typeof result === 'object' ? result : testObject;
console.log(testObject instanceof MyObject); // returns true
console.log(result instanceof MyObject); // returns false because it's actually prop (i.e. {})
What we have done is replace the new with the actual steps that happen when you do a new. Below are the steps
Create an object whose prototype is the same as the function's (constructor's) prototype. This is what var testObject = Object.create(MyObject.prototype);
Call the (constructor) function with this set to this newly created object. This what var result = MyObject.call(testObject); does (the first parameter being the value of this for the MyObject invocation)
If the function returns a non null object, the new ... expression evaluates to that value. Otherwise it evaluates to the object created in Step 1.
For the question, the last step's non null return value (prop = {}) was getting in the way of our actually testing the type of the object returned in Step 1. By splitting it into component steps we can get the created object (and use that in the instanceOf test)
If you can at least modify prop, then you could add a flag to it:
var MyObject = function() {
var prop = { _isMyObject: true }
return prop;
};
Then you could have a function that checks for that flag.
function isMyObject(obj) {
return obj._isMyObject ? true : false;
}
You will see why if you try this:
var MyObject = function() {
var prop = { testProp: 1 };
return prop;
}
var testObject = new MyObject();
console.log(testObject.testProp); // returns 1;
If in a class constructor you return an object, the newly instantiated object of that will become that returned object. If you return a primitive value, it will instead become an instance of the object as your originally expected.
So, if you apply Object.prototype.toString() method on your prop object and instead return the result of that (a string primitive), you get your desired MyObject back:
var MyObject = function() {
var prop = {};
return prop.toString();
}
var testObject = new MyObject();
console.log(testObject instanceof MyObject); // returns true;
It's because when you do
var MyObject = function() {
var prop = {};
return prop;
}
you are assigning a function to the variable MyObject. Not creating a custom object MyObject. In order to create a custom object, you need to use the syntax
function MyObject() {
var prop = {};
return prop;
}
var testObject = new MyObject();
console.log(testObject instanceof MyObject); // return true;
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof
I need to loop over the properties of a javascript object. How can I tell if a property is a function or just a value?
var model =
{
propertyA: 123,
propertyB: function () { return 456; }
};
for (var property in model)
{
var value;
if(model[property] is function) //how can I tell if it is a function???
value = model[property]();
else
value = model[property];
}
Use the typeof operator:
if (typeof model[property] == 'function') ...
Also, note that you should be sure that the properties you are iterating are part of this object, and not inherited as a public property on the prototype of some other object up the inheritance chain:
for (var property in model){
if (!model.hasOwnProperty(property)) continue;
...
}
Following might be useful to you, I think.
How can I check if a javascript variable is function type?
BTW, I am using following to check for the function.
// Test data
var f1 = function () { alert("test"); }
var o1 = { Name: "Object_1" };
F_est = function () { };
var o2 = new F_est();
// Results
alert(f1 instanceof Function); // true
alert(o1 instanceof Function); // false
alert(o2 instanceof Function); // false
You can use the following solution to check if a JavaScript variable is a function:
var model =
{
propertyA: 123,
propertyB: function () { return 456; }
};
for (var property in model)
{
var value;
if(typeof model[property] == 'function') // Like so!
else
value = model[property];
}
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
var o1 = {};
o1.init = function(){
alert('o1');
};
var o2 = Object.create(o1);
o2.init = function(){
// how would I call my ancessors init()?
alert('o2');
};
o2.init();
JavaScript functions are objects and have two useful methods to invoke the function:
Function.call(scope, [arg1, ...])
Function.apply(scope, args)
You can use one of these to call the parent implementation, explicitely passing this as the scope parameter, so that in the parent implementation, this refers to the child object:
var o1 = {
name : "One",
init : function() {
alert("o1: " + this.name);
}
};
var o2 = Object.create(o1);
o2.name = "Two";
o2.init = function() {
o1.init.call(this);
alert("o2: " + this name);
};
This will alert: o1: Two and o2: Two.
Maybe this is oversimplifying what you’re trying to accomplish ... would placing o1.init() in the o2 init function work?
o2.init = function(){
// how would I call my ancessors init()?
alert('o2');
o1.init();
};
Out of curiosity, was "ancessors" a spelling error for "ancestor’s" or does "ancessors" mean something specific here? Did you mean o2’s "parent" object?
In browsers that support it, you could use the Object.getPrototypeOf function, like this:
o2.init = function(){
Object.getPrototypeOf(this).init.call(this);
alert('o2');
};
This would get the prototype of o2 (o1) and apply its init method to this (o2), just like a super.init() in other languages.
UPDATE:
The Object.getPrototypeOf function could be implemented like this:
if ( typeof Object.getPrototypeOf !== "function" )
{
if ( typeof ({}).__proto__ === "object" )
{
Object.getPrototypeOf = function(object)
{
return object.__proto__;
};
}
else
{
Object.getPrototypeOf = function(object)
{
// May break if the constructor has been tampered with
return object.constructor.prototype;
};
}
}
Found on this link: http://ejohn.org/blog/objectgetprototypeof/