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 am writing some code to extend Object, and I would like to loop over the methods within the object. When I output the value of this.constructor, I see the methods that I would like (in the example below I see test). However, when I loop over the methods using a for, it only displays the method getType. How can I get just the methods of class A?
Object.prototype.getType = function () {
// Outputs correct class and methods
console.log(this.constructor)
for (let i in this.constructor) {
// Outputs wrong methods
console.log(i)
}
}
class A {
test() {console.log('hello')}
}
new A().getType()
Two problems:
Properties can be enumerable – visited by for…in loops – or not. When you define a method in a class, the default is non-enumerable. (Object.prototype.getType, on the other hand, is enumerable because that’s the default when you create a property by assignment.)
You’re looping over properties of what the object claims is its constructor, but non-static methods like test are properties of the constructor’s prototype property (A.prototype), not the constructor itself (A.test isn’t a thing).
You can find non-enumerable properties with the Object.getOwnPropertyNames function:
Object.prototype.getType = function () {
for (let name of Object.getOwnPropertyNames(this.constructor.prototype)) {
console.log(name)
}
}
Note that this only includes own properties – properties directly on the object – so if you want to include inherited methods, you’ll have to go up the prototype chain.
function* getAllPropertyNames(obj) {
do {
yield* Object.getOwnPropertyNames(obj)
} while (obj = Object.getPrototypeOf(obj))
}
Object.prototype.getType = function () {
for (let name of getAllPropertyNames(this.constructor.prototype)) {
console.log(name)
}
}
And if you want to include properties directly on the object, you’ll have to start there (and hope this.constructor.prototype is Object.getPrototypeOf(this)).
Object.prototype.getType = function () {
for (let name of getAllPropertyNames(this)) {
console.log(name)
}
}
Also, don’t extend Object.prototype. Especially not with enumerable properties. Management is not responsible for dependencies that break in mysterious ways when you do this.
Perhaps not the most elegant solution, but one way to do this is via a call to Object.getOwnPropertyNames(), passing the object instances __proto__ reference.
Object.prototype.getType = function () {
/*
// Outputs correct class and methods
console.log(this.constructor)
for (let i in this.constructor) {
// Outputs wrong methods
console.log(i)
}
*/
for(let j of Object.getOwnPropertyNames(this.__proto__)
.filter(method => method !== 'constructor'))
{
// Outputs properties of prototype, without constructor method
console.log(j);
}
}
class A {
test() {console.log('hello')}
}
new A().getType()
The getType name seems inappropriate, what you're looking for are properties, so getAllProperties seems a better name.
As others have said, you need to go up the [[Prototype]] chain for a number of reasons:
Objects inherit from their constructor's prototype, not the constructor itself
The constructor property may not point to the actual constructor
The constructor.prototype may not be the one used to create the object
There may be multiple constructors
Inherited properties may be duplicated, you need to get just the "closest" one
The [[Prototype]] chain ends in null, which is the prototype for Object.prototype and is the top of all prototype hierarchies. The function should also remove duplicates, which can occur on each prototype (e.g. constructor, and length is pretty common).
function getAllProperties(obj) {
// Recursively get properties up [[Prototype]] chain
function loop(obj) {
let props = Object.getOwnPropertyNames(obj);
let proto = Object.getPrototypeOf(obj);
// Stop at null
if (proto !== null) {
return props.concat(loop(proto));
}
return props;
}
let allProps = loop(obj);
// Remove duplicates
return allProps.filter((prop, i) => !allProps.includes(prop, i+1));
}
console.log(getAllProperties('a'))
If you want just methods, then filter as you go for typeof x == 'function':
function getAllMethods(obj) {
// Recursively get properties up [[Prototype]] chain
function loop(obj) {
// Get all properties, filter for functions
let props = Object.getOwnPropertyNames(obj).filter((prop, i, props) => typeof props[prop] == 'function');
let proto = Object.getPrototypeOf(obj);
// Stop at null
if (proto !== null) {
return props.concat(loop(proto));
}
return props;
}
let allMethods = loop(obj);
// Remove duplicates
return allMethods.filter((prop, i) => !allMethods.includes(prop, i + 1));
}
console.log(getAllMethods('a'))
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've come to a point where I need to have some sort of rudimentary multiple inheritance happening in JavaScript. (I'm not here to discuss whether this is a good idea or not, so please kindly keep those comments to yourself.)
I just want to know if anyone's attempted this with any (or not) success, and how they went about it.
To boil it down, what I really need is to be able to have an object capable of inheriting a property from more than one prototype chain (i.e. each prototype could have its own proper chain), but in a given order of precedence (it will search the chains in order for the first definition).
To demonstrate how this is theoretically possible, it could be achieved by attaching the secondary chain onto the end of the primary chain, but this would affect all instances of any of those previous prototypes and that's not what I want.
Thoughts?
Multiple inheritance can be achieved in ECMAScript 6 by using Proxy objects.
Implementation
function getDesc (obj, prop) {
var desc = Object.getOwnPropertyDescriptor(obj, prop);
return desc || (obj=Object.getPrototypeOf(obj) ? getDesc(obj, prop) : void 0);
}
function multiInherit (...protos) {
return Object.create(new Proxy(Object.create(null), {
has: (target, prop) => protos.some(obj => prop in obj),
get (target, prop, receiver) {
var obj = protos.find(obj => prop in obj);
return obj ? Reflect.get(obj, prop, receiver) : void 0;
},
set (target, prop, value, receiver) {
var obj = protos.find(obj => prop in obj);
return Reflect.set(obj || Object.create(null), prop, value, receiver);
},
*enumerate (target) { yield* this.ownKeys(target); },
ownKeys(target) {
var hash = Object.create(null);
for(var obj of protos) for(var p in obj) if(!hash[p]) hash[p] = true;
return Object.getOwnPropertyNames(hash);
},
getOwnPropertyDescriptor(target, prop) {
var obj = protos.find(obj => prop in obj);
var desc = obj ? getDesc(obj, prop) : void 0;
if(desc) desc.configurable = true;
return desc;
},
preventExtensions: (target) => false,
defineProperty: (target, prop, desc) => false,
}));
}
Explanation
A proxy object consists of a target object and some traps, which define custom behavior for fundamental operations.
When creating an object which inherits from another one, we use Object.create(obj). But in this case we want multiple inheritance, so instead of obj I use a proxy that will redirect fundamental operations to the appropriate object.
I use these traps:
The has trap is a trap for the in operator. I use some to check if at least one prototype contains the property.
The get trap is a trap for getting property values. I use find to find the first prototype which contains that property, and I return the value, or call the getter on the appropriate receiver. This is handled by Reflect.get. If no prototype contains the property, I return undefined.
The set trap is a trap for setting property values. I use find to find the first prototype which contains that property, and I call its setter on the appropriate receiver. If there is no setter or no prototype contains the property, the value is defined on the appropriate receiver. This is handled by Reflect.set.
The enumerate trap is a trap for for...in loops. I iterate the enumerable properties from the first prototype, then from the second, and so on. Once a property has been iterated, I store it in a hash table to avoid iterating it again.
Warning: This trap has been removed in ES7 draft and is deprecated in browsers.
The ownKeys trap is a trap for Object.getOwnPropertyNames(). Since ES7, for...in loops keep calling [[GetPrototypeOf]] and getting the own properties of each one. So in order to make it iterate the properties of all prototypes, I use this trap to make all enumerable inherited properties appear like own properties.
The getOwnPropertyDescriptor trap is a trap for Object.getOwnPropertyDescriptor(). Making all enumerable properties appear like own properties in the ownKeys trap is not enough, for...in loops will get the descriptor to check if they are enumerable. So I use find to find the first prototype which contains that property, and I iterate its prototypical chain until I find the property owner, and I return its descriptor. If no prototype contains the property, I return undefined. The descriptor is modified to make it configurable, otherwise we could break some proxy invariants.
The preventExtensions and defineProperty traps are only included to prevent these operations from modifying the proxy target. Otherwise we could end up breaking some proxy invariants.
There are more traps available, which I don't use
The getPrototypeOf trap could be added, but there is no proper way to return the multiple prototypes. This implies instanceof won't work neither. Therefore, I let it get the prototype of the target, which initially is null.
The setPrototypeOf trap could be added and accept an array of objects, which would replace the prototypes. This is left as an exercice for the reader. Here I just let it modify the prototype of the target, which is not much useful because no trap uses the target.
The deleteProperty trap is a trap for deleting own properties. The proxy represents the inheritance, so this wouldn't make much sense. I let it attempt the deletion on the target, which should have no property anyway.
The isExtensible trap is a trap for getting the extensibility. Not much useful, given that an invariant forces it to return the same extensibility as the target. So I just let it redirect the operation to the target, which will be extensible.
The apply and construct traps are traps for calling or instantiating. They are only useful when the target is a function or a constructor.
Example
// Creating objects
var o1, o2, o3,
obj = multiInherit(o1={a:1}, o2={b:2}, o3={a:3, b:3});
// Checking property existences
'a' in obj; // true (inherited from o1)
'b' in obj; // true (inherited from o2)
'c' in obj; // false (not found)
// Setting properties
obj.c = 3;
// Reading properties
obj.a; // 1 (inherited from o1)
obj.b; // 2 (inherited from o2)
obj.c; // 3 (own property)
obj.d; // undefined (not found)
// The inheritance is "live"
obj.a; // 1 (inherited from o1)
delete o1.a;
obj.a; // 3 (inherited from o3)
// Property enumeration
for(var p in obj) p; // "c", "b", "a"
Update (2019): The original post is getting pretty outdated. This article (now internet archive link, since domain went away) and its associated GitHub library are a good modern approach.
Original post:
Multiple inheritance [edit, not proper inheritance of type, but of properties; mixins] in Javascript is pretty straightforward if you use constructed prototypes rather than generic-object ones. Here are two parent classes to inherit from:
function FoodPrototype() {
this.eat = function () {
console.log("Eating", this.name);
};
}
function Food(name) {
this.name = name;
}
Food.prototype = new FoodPrototype();
function PlantPrototype() {
this.grow = function () {
console.log("Growing", this.name);
};
}
function Plant(name) {
this.name = name;
}
Plant.prototype = new PlantPrototype();
Note that I have used the same "name" member in each case, which could be a problem if the parents did not agree about how "name" should be handled. But they're compatible (redundant, really) in this case.
Now we just need a class that inherits from both. Inheritance is done by calling the constructor function (without using the new keyword) for the prototypes and the object constructors. First, the prototype has to inherit from the parent prototypes
function FoodPlantPrototype() {
FoodPrototype.call(this);
PlantPrototype.call(this);
// plus a function of its own
this.harvest = function () {
console.log("harvest at", this.maturity);
};
}
And the constructor has to inherit from the parent constructors:
function FoodPlant(name, maturity) {
Food.call(this, name);
Plant.call(this, name);
// plus a property of its own
this.maturity = maturity;
}
FoodPlant.prototype = new FoodPlantPrototype();
Now you can grow, eat, and harvest different instances:
var fp1 = new FoodPlant('Radish', 28);
var fp2 = new FoodPlant('Corn', 90);
fp1.grow();
fp2.grow();
fp1.harvest();
fp1.eat();
fp2.harvest();
fp2.eat();
This one uses Object.create to make a real prototype chain:
function makeChain(chains) {
var c = Object.prototype;
while(chains.length) {
c = Object.create(c);
$.extend(c, chains.pop()); // some function that does mixin
}
return c;
}
For example:
var obj = makeChain([{a:1}, {a: 2, b: 3}, {c: 4}]);
will return:
a: 1
a: 2
b: 3
c: 4
<Object.prototype stuff>
so that obj.a === 1, obj.b === 3, etc.
I like John Resig's implementation of a class structure: http://ejohn.org/blog/simple-javascript-inheritance/
This can be simply extended to something like:
Class.extend = function(prop /*, prop, prop, prop */) {
for( var i=1, l=arguments.length; i<l; i++ ){
prop = $.extend( prop, arguments[i] );
}
// same code
}
which will allow you to pass in multiple objects of which to inherit. You're going to lose instanceOf capability here, but that's a given if you want multiple inheritance.
my rather convoluted example of the above is available at https://github.com/cwolves/Fetch/blob/master/support/plugins/klass/klass.js
Note that there is some dead code in that file, but it allows multiple inheritance if you want to take a look.
If you want chained inheritance (NOT multiple inheritance, but for most people it's the same thing), it can be accomplished with Class like:
var newClass = Class.extend( cls1 ).extend( cls2 ).extend( cls3 )
which will preserve the original prototype chain, but you'll also have a lot of pointless code running.
I offer a function to allow classes to be defined with multiple inheritance. It allows for code like the following:
let human = new Running({ name: 'human', numLegs: 2 });
human.run();
let airplane = new Flying({ name: 'airplane', numWings: 2 });
airplane.fly();
let dragon = new RunningFlying({ name: 'dragon', numLegs: 4, numWings: 6 });
dragon.takeFlight();
to produce output like this:
human runs with 2 legs.
airplane flies away with 2 wings!
dragon runs with 4 legs.
dragon flies away with 6 wings!
Here are what the class definitions look like:
let Named = makeClass('Named', {}, () => ({
init: function({ name }) {
this.name = name;
}
}));
let Running = makeClass('Running', { Named }, protos => ({
init: function({ name, numLegs }) {
protos.Named.init.call(this, { name });
this.numLegs = numLegs;
},
run: function() {
console.log(`${this.name} runs with ${this.numLegs} legs.`);
}
}));
let Flying = makeClass('Flying', { Named }, protos => ({
init: function({ name, numWings }) {
protos.Named.init.call(this, { name });
this.numWings = numWings;
},
fly: function( ){
console.log(`${this.name} flies away with ${this.numWings} wings!`);
}
}));
let RunningFlying = makeClass('RunningFlying', { Running, Flying }, protos => ({
init: function({ name, numLegs, numWings }) {
protos.Running.init.call(this, { name, numLegs });
protos.Flying.init.call(this, { name, numWings });
},
takeFlight: function() {
this.run();
this.fly();
}
}));
We can see that each class definition using the makeClass function accepts an Object of parent-class names mapped to parent-classes. It also accepts a function that returns an Object containing properties for the class being defined. This function has a parameter protos, which contains enough information to access any property defined by any of the parent-classes.
The final piece required is the makeClass function itself, which does quite a bit of work. Here it is, along with the rest of the code. I've commented makeClass quite heavily:
let makeClass = (name, parents={}, propertiesFn=()=>({})) => {
// The constructor just curries to a Function named "init"
let Class = function(...args) { this.init(...args); };
// This allows instances to be named properly in the terminal
Object.defineProperty(Class, 'name', { value: name });
// Tracking parents of `Class` allows for inheritance queries later
Class.parents = parents;
// Initialize prototype
Class.prototype = Object.create(null);
// Collect all parent-class prototypes. `Object.getOwnPropertyNames`
// will get us the best results. Finally, we'll be able to reference
// a property like "usefulMethod" of Class "ParentClass3" with:
// `parProtos.ParentClass3.usefulMethod`
let parProtos = {};
for (let parName in parents) {
let proto = parents[parName].prototype;
parProtos[parName] = {};
for (let k of Object.getOwnPropertyNames(proto)) {
parProtos[parName][k] = proto[k];
}
}
// Resolve `properties` as the result of calling `propertiesFn`. Pass
// `parProtos`, so a child-class can access parent-class methods, and
// pass `Class` so methods of the child-class have a reference to it
let properties = propertiesFn(parProtos, Class);
properties.constructor = Class; // Ensure "constructor" prop exists
// If two parent-classes define a property under the same name, we
// have a "collision". In cases of collisions, the child-class *must*
// define a method (and within that method it can decide how to call
// the parent-class methods of the same name). For every named
// property of every parent-class, we'll track a `Set` containing all
// the methods that fall under that name. Any `Set` of size greater
// than one indicates a collision.
let propsByName = {}; // Will map property names to `Set`s
for (let parName in parProtos) {
for (let propName in parProtos[parName]) {
// Now track the property `parProtos[parName][propName]` under the
// label of `propName`
if (!propsByName.hasOwnProperty(propName))
propsByName[propName] = new Set();
propsByName[propName].add(parProtos[parName][propName]);
}
}
// For all methods defined by the child-class, create or replace the
// entry in `propsByName` with a Set containing a single item; the
// child-class' property at that property name (this also guarantees
// there is no collision at this property name). Note property names
// prefixed with "$" will be considered class properties (and the "$"
// will be removed).
for (let propName in properties) {
if (propName[0] === '$') {
// The "$" indicates a class property; attach to `Class`:
Class[propName.slice(1)] = properties[propName];
} else {
// No "$" indicates an instance property; attach to `propsByName`:
propsByName[propName] = new Set([ properties[propName] ]);
}
}
// Ensure that "init" is defined by a parent-class or by the child:
if (!propsByName.hasOwnProperty('init'))
throw Error(`Class "${name}" is missing an "init" method`);
// For each property name in `propsByName`, ensure that there is no
// collision at that property name, and if there isn't, attach it to
// the prototype! `Object.defineProperty` can ensure that prototype
// properties won't appear during iteration with `in` keyword:
for (let propName in propsByName) {
let propsAtName = propsByName[propName];
if (propsAtName.size > 1)
throw new Error(`Class "${name}" has conflict at "${propName}"`);
Object.defineProperty(Class.prototype, propName, {
enumerable: false,
writable: true,
value: propsAtName.values().next().value // Get 1st item in Set
});
}
return Class;
};
let Named = makeClass('Named', {}, () => ({
init: function({ name }) {
this.name = name;
}
}));
let Running = makeClass('Running', { Named }, protos => ({
init: function({ name, numLegs }) {
protos.Named.init.call(this, { name });
this.numLegs = numLegs;
},
run: function() {
console.log(`${this.name} runs with ${this.numLegs} legs.`);
}
}));
let Flying = makeClass('Flying', { Named }, protos => ({
init: function({ name, numWings }) {
protos.Named.init.call(this, { name });
this.numWings = numWings;
},
fly: function( ){
console.log(`${this.name} flies away with ${this.numWings} wings!`);
}
}));
let RunningFlying = makeClass('RunningFlying', { Running, Flying }, protos => ({
init: function({ name, numLegs, numWings }) {
protos.Running.init.call(this, { name, numLegs });
protos.Flying.init.call(this, { name, numWings });
},
takeFlight: function() {
this.run();
this.fly();
}
}));
let human = new Running({ name: 'human', numLegs: 2 });
human.run();
let airplane = new Flying({ name: 'airplane', numWings: 2 });
airplane.fly();
let dragon = new RunningFlying({ name: 'dragon', numLegs: 4, numWings: 6 });
dragon.takeFlight();
The makeClass function also supports class properties; these are defined by prefixing property names with the $ symbol (note that the final property name that results will have the $ removed). With this in mind, we could write a specialized Dragon class that models the "type" of the Dragon, where the list of available Dragon types is stored on the Class itself, as opposed to on the instances:
let Dragon = makeClass('Dragon', { RunningFlying }, protos => ({
$types: {
wyvern: 'wyvern',
drake: 'drake',
hydra: 'hydra'
},
init: function({ name, numLegs, numWings, type }) {
protos.RunningFlying.init.call(this, { name, numLegs, numWings });
this.type = type;
},
description: function() {
return `A ${this.type}-type dragon with ${this.numLegs} legs and ${this.numWings} wings`;
}
}));
let dragon1 = new Dragon({ name: 'dragon1', numLegs: 2, numWings: 4, type: Dragon.types.drake });
let dragon2 = new Dragon({ name: 'dragon2', numLegs: 4, numWings: 2, type: Dragon.types.hydra });
The Challenges of Multiple Inheritance
Anyone who followed the code for makeClass closely will note a rather significant undesirable phenomenon occurring silently when the above code runs: instantiating a RunningFlying will result in TWO calls to the Named constructor!
This is because the inheritance graph looks like this:
(^^ More Specialized ^^)
RunningFlying
/ \
/ \
Running Flying
\ /
\ /
Named
(vv More Abstract vv)
When there are multiple paths to the same parent-class in a sub-class' inheritance graph, instantiations of the sub-class will invoke that parent-class' constructor multiple times.
Combatting this is non-trivial. Let's look at some examples with simplified classnames. We'll consider class A, the most abstract parent-class, classes B and C, which both inherit from A, and class BC which inherits from B and C (and hence conceptually "double-inherits" from A):
let A = makeClass('A', {}, () => ({
init: function() {
console.log('Construct A');
}
}));
let B = makeClass('B', { A }, protos => ({
init: function() {
protos.A.init.call(this);
console.log('Construct B');
}
}));
let C = makeClass('C', { A }, protos => ({
init: function() {
protos.A.init.call(this);
console.log('Construct C');
}
}));
let BC = makeClass('BC', { B, C }, protos => ({
init: function() {
// Overall "Construct A" is logged twice:
protos.B.init.call(this); // -> console.log('Construct A'); console.log('Construct B');
protos.C.init.call(this); // -> console.log('Construct A'); console.log('Construct C');
console.log('Construct BC');
}
}));
If we want to prevent BC from double-invoking A.prototype.init we may need to abandon the style of directly calling inherited constructors. We will need some level of indirection to check whether duplicate calls are occurring, and short-circuit before they happen.
We could consider changing the parameters supplied to the properties function: alongside protos, an Object containing raw data describing inherited properties, we could also include a utility function for calling an instance method in such a way that parent methods are also called, but duplicate calls are detected and prevented. Let's take a look at where we establish the parameters for the propertiesFn Function:
let makeClass = (name, parents, propertiesFn) => {
/* ... a bunch of makeClass logic ... */
// Allows referencing inherited functions; e.g. `parProtos.ParentClass3.usefulMethod`
let parProtos = {};
/* ... collect all parent methods in `parProtos` ... */
// Utility functions for calling inherited methods:
let util = {};
util.invokeNoDuplicates = (instance, fnName, args, dups=new Set()) => {
// Invoke every parent method of name `fnName` first...
for (let parName of parProtos) {
if (parProtos[parName].hasOwnProperty(fnName)) {
// Our parent named `parName` defines the function named `fnName`
let fn = parProtos[parName][fnName];
// Check if this function has already been encountered.
// This solves our duplicate-invocation problem!!
if (dups.has(fn)) continue;
dups.add(fn);
// This is the first time this Function has been encountered.
// Call it on `instance`, with the desired args. Make sure we
// include `dups`, so that if the parent method invokes further
// inherited methods we don't lose track of what functions have
// have already been called.
fn.call(instance, ...args, dups);
}
}
};
// Now we can call `propertiesFn` with an additional `util` param:
// Resolve `properties` as the result of calling `propertiesFn`:
let properties = propertiesFn(parProtos, util, Class);
/* ... a bunch more makeClass logic ... */
};
The whole purpose of the above change to makeClass is so that we have an additional argument supplied to our propertiesFn when we invoke makeClass. We should also be aware that every function defined in any class may now receive a parameter after all its others, named dup, which is a Set that holds all functions that have already been called as a result of calling the inherited method:
let A = makeClass('A', {}, () => ({
init: function() {
console.log('Construct A');
}
}));
let B = makeClass('B', { A }, (protos, util) => ({
init: function(dups) {
util.invokeNoDuplicates(this, 'init', [ /* no args */ ], dups);
console.log('Construct B');
}
}));
let C = makeClass('C', { A }, (protos, util) => ({
init: function(dups) {
util.invokeNoDuplicates(this, 'init', [ /* no args */ ], dups);
console.log('Construct C');
}
}));
let BC = makeClass('BC', { B, C }, (protos, util) => ({
init: function(dups) {
util.invokeNoDuplicates(this, 'init', [ /* no args */ ], dups);
console.log('Construct BC');
}
}));
This new style actually succeeds in ensuring "Construct A" is only logged once when an instance of BC is initialized. But there are three downsides, the third of which is very critical:
This code has become less readable and maintainable. A lot of complexity hides behind the util.invokeNoDuplicates function, and thinking about how this style avoids multi-invocation is non-intuitive and headache inducing. We also have that pesky dups parameter, which really needs to be defined on every single function in the class. Ouch.
This code is slower - quite a bit more indirection and computation is required to achieve desirable results with multiple inheritance. Unfortunately this is likely to be the case with any solution to our multiple-invocation problem.
Most significantly, the structure of functions which rely on inheritance has become very rigid. If a sub-class NiftyClass overrides a function niftyFunction, and uses util.invokeNoDuplicates(this, 'niftyFunction', ...) to run it without duplicate-invocation, NiftyClass.prototype.niftyFunction will call the function named niftyFunction of every parent class that defines it, ignore any return values from those classes, and finally perform the specialized logic of NiftyClass.prototype.niftyFunction. This is the only possible structure. If NiftyClass inherits CoolClass and GoodClass, and both these parent-classes provide niftyFunction definitions of their own, NiftyClass.prototype.niftyFunction will never (without risking multiple-invocation) be able to:
A. Run the specialized logic of NiftyClass first, then the specialized logic of parent-classes
B. Run the specialized logic of NiftyClass at any point other than after all specialized parent logic has completed
C. Behave conditionally depending on the return values of its parent's specialized logic
D. Avoid running a particular parent's specialized niftyFunction altogether
Of course, we could solve each lettered problem above by defining specialized functions under util:
A. define util.invokeNoDuplicatesSubClassLogicFirst(instance, fnName, ...)
B. define util.invokeNoDuplicatesSubClassAfterParent(parentName, instance, fnName, ...) (Where parentName is the name of the parent whose specialized logic will be immediately followed by the child-classes' specialized logic)
C. define util.invokeNoDuplicatesCanShortCircuitOnParent(parentName, testFn, instance, fnName, ...) (In this case testFn would receive the result of the specialized logic for the parent named parentName, and would return a true/false value indicating whether the short-circuit should happen)
D. define util.invokeNoDuplicatesBlackListedParents(blackList, instance, fnName, ...) (In this case blackList would be an Array of parent names whose specialized logic should be skipped altogether)
These solutions are all available, but this is total mayhem! For every unique structure that an inherited function call can take, we would need a specialized method defined under util. What an absolute disaster.
With this in mind we can start to see the challenges of implementing good multiple inheritance. The full implementation of makeClass I provided in this answer does not even consider the multiple-invocation problem, or many other problems which arise regarding multiple inheritance.
This answer is getting very long. I hope the makeClass implementation I included is still useful, even if it isn't perfect. I also hope anyone interested in this topic has gained more context to keep in mind as they do further reading!
Don't get confused with JavaScript framework implementations of multiple inheritance.
All you need to do is use Object.create() to create a new object each time with the specified prototype object and properties, then be sure to change the Object.prototype.constructor each step of the way if you plan on instantiating B in the future.
To inherit instance properties thisA and thisB we use Function.prototype.call() at the end of each object function. This is optional if you only care about inheriting the prototype.
Run the following code somewhere and observe objC:
function A() {
this.thisA = 4; // objC will contain this property
}
A.prototype.a = 2; // objC will contain this property
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
function B() {
this.thisB = 55; // objC will contain this property
A.call(this);
}
B.prototype.b = 3; // objC will contain this property
C.prototype = Object.create(B.prototype);
C.prototype.constructor = C;
function C() {
this.thisC = 123; // objC will contain this property
B.call(this);
}
C.prototype.c = 2; // objC will contain this property
var objC = new C();
B inherits the prototype from A
C inherits the prototype from B
objC is an instance of C
This is a good explanation of the steps above:
OOP In JavaScript: What You NEED to Know
I’m in no way an expert on javascript OOP, but if I understand you correctly you want something like (pseudo-code):
Earth.shape = 'round';
Animal.shape = 'random';
Cat inherit from (Earth, Animal);
Cat.shape = 'random' or 'round' depending on inheritance order;
In that case, I’d try something like:
var Earth = function(){};
Earth.prototype.shape = 'round';
var Animal = function(){};
Animal.prototype.shape = 'random';
Animal.prototype.head = true;
var Cat = function(){};
MultiInherit(Cat, Earth, Animal);
console.log(new Cat().shape); // yields "round", since I reversed the inheritance order
console.log(new Cat().head); // true
function MultiInherit() {
var c = [].shift.call(arguments),
len = arguments.length
while(len--) {
$.extend(c.prototype, new arguments[len]());
}
}
It's possible to implement multiple inheritance in JavaScript, although very few libraries does it.
I could point Ring.js, the only example I know.
I was working on this a lot today and trying to achieve this myself in ES6. The way I did it was using Browserify, Babel and then I tested it with Wallaby and it seemed to work. My goal is to extend the current Array, include ES6, ES7 and add some additional custom features I need in the prototype for dealing with audio data.
Wallaby passes 4 of my tests. The example.js file can be pasted in the console and you can see that the 'includes' property is in the prototype of the class. I still want to test this more tomorrow.
Here's my method: (I will most likely refactor and repackage as a module after some sleep!)
var includes = require('./polyfills/includes');
var keys = Object.getOwnPropertyNames(includes.prototype);
keys.shift();
class ArrayIncludesPollyfills extends Array {}
function inherit (...keys) {
keys.map(function(key){
ArrayIncludesPollyfills.prototype[key]= includes.prototype[key];
});
}
inherit(keys);
module.exports = ArrayIncludesPollyfills
Github Repo:
https://github.com/danieldram/array-includes-polyfill
I think it is ridiculously simple. The issue here is that the child class will only refer to instanceof for the first class you call
https://jsfiddle.net/1033xzyt/19/
function Foo() {
this.bar = 'bar';
return this;
}
Foo.prototype.test = function(){return 1;}
function Bar() {
this.bro = 'bro';
return this;
}
Bar.prototype.test2 = function(){return 2;}
function Cool() {
Foo.call(this);
Bar.call(this);
return this;
}
var combine = Object.create(Foo.prototype);
$.extend(combine, Object.create(Bar.prototype));
Cool.prototype = Object.create(combine);
Cool.prototype.constructor = Cool;
var cool = new Cool();
console.log(cool.test()); // 1
console.log(cool.test2()); //2
console.log(cool.bro) //bro
console.log(cool.bar) //bar
console.log(cool instanceof Foo); //true
console.log(cool instanceof Bar); //false
Check the code below which IS showing support for multiple inheritance. Done by using PROTOTYPAL INHERITANCE
function A(name) {
this.name = name;
}
A.prototype.setName = function (name) {
this.name = name;
}
function B(age) {
this.age = age;
}
B.prototype.setAge = function (age) {
this.age = age;
}
function AB(name, age) {
A.prototype.setName.call(this, name);
B.prototype.setAge.call(this, age);
}
AB.prototype = Object.assign({}, Object.create(A.prototype), Object.create(B.prototype));
AB.prototype.toString = function () {
return `Name: ${this.name} has age: ${this.age}`
}
const a = new A("shivang");
const b = new B(32);
console.log(a.name);
console.log(b.age);
const ab = new AB("indu", 27);
console.log(ab.toString());
Take a look of the package IeUnit.
The concept assimilation implemented in IeUnit seems to offers what you are looking for in a quite dynamical way.
Here is an example of prototype chaining using constructor functions:
function Lifeform () { // 1st Constructor function
this.isLifeform = true;
}
function Animal () { // 2nd Constructor function
this.isAnimal = true;
}
Animal.prototype = new Lifeform(); // Animal is a lifeform
function Mammal () { // 3rd Constructor function
this.isMammal = true;
}
Mammal.prototype = new Animal(); // Mammal is an animal
function Cat (species) { // 4th Constructor function
this.isCat = true;
this.species = species
}
Cat.prototype = new Mammal(); // Cat is a mammal
This concept uses Yehuda Katz's definition of a "class" for JavaScript:
...a JavaScript "class" is just a Function object that serves as a constructor plus an attached prototype object. (Source: Guru Katz)
Unlike the Object.create approach, when the classes are built in this way and we want to create instances of a "class", we don't need to know what each "class" is inheriting from. We just use new.
// Make an instance object of the Cat "Class"
var tiger = new Cat("tiger");
console.log(tiger.isCat, tiger.isMammal, tiger.isAnimal, tiger.isLifeform);
// Outputs: true true true true
The order of precendence should make sense. First it looks in the instance object, then it's prototype, then the next prototype, etc.
// Let's say we have another instance, a special alien cat
var alienCat = new Cat("alien");
// We can define a property for the instance object and that will take
// precendence over the value in the Mammal class (down the chain)
alienCat.isMammal = false;
// OR maybe all cats are mutated to be non-mammals
Cat.prototype.isMammal = false;
console.log(alienCat);
We can also modify the prototypes which will effect all objects built on the class.
// All cats are mutated to be non-mammals
Cat.prototype.isMammal = false;
console.log(tiger, alienCat);
I originally wrote some of this up with this answer.
A latecomer in the scene is SimpleDeclare. However, when dealing with multiple inheritance, you will still end up with copies of the original constructors. That's a necessity in Javascript...
Merc.
I would use ds.oop. Its similar to prototype.js and others. makes multiple inheritance very easy and its minimalist. (only 2 or 3 kb) Also supports some other neat features like interfaces and dependency injection
/*** multiple inheritance example ***********************************/
var Runner = ds.class({
run: function() { console.log('I am running...'); }
});
var Walker = ds.class({
walk: function() { console.log('I am walking...'); }
});
var Person = ds.class({
inherits: [Runner, Walker],
eat: function() { console.log('I am eating...'); }
});
var person = new Person();
person.run();
person.walk();
person.eat();
How about this, it implements multiple inheritance in JavaScript:
class Car {
constructor(brand) {
this.carname = brand;
}
show() {
return 'I have a ' + this.carname;
}
}
class Asset {
constructor(price) {
this.price = price;
}
show() {
return 'its estimated price is ' + this.price;
}
}
class Model_i1 { // extends Car and Asset (just a comment for ourselves)
//
constructor(brand, price, usefulness) {
specialize_with(this, new Car(brand));
specialize_with(this, new Asset(price));
this.usefulness = usefulness;
}
show() {
return Car.prototype.show.call(this) + ", " + Asset.prototype.show.call(this) + ", Model_i1";
}
}
mycar = new Model_i1("Ford Mustang", "$100K", 16);
document.getElementById("demo").innerHTML = mycar.show();
And here's the code for specialize_with() utility function:
function specialize_with(o, S) { for (var prop in S) { o[prop] = S[prop]; } }
This is real code that runs. You can copy-paste it in html file, and try it yourself. It does work.
That's the effort to implement MI in JavaScript. Not much of code, more of a know-how.
Please feel free to look at my complete article on this, https://github.com/latitov/OOP_MI_Ct_oPlus_in_JS
I just used to assign what classes I need in properties of others, and add a proxy to auto-point to them i like:
class A {
constructor()
{
this.test = "a test";
}
method()
{
console.log("in the method");
}
}
class B {
constructor()
{
this.extends = [new A()];
return new Proxy(this, {
get: function(obj, prop) {
if(prop in obj)
return obj[prop];
let response = obj.extends.find(function (extended) {
if(prop in extended)
return extended[prop];
});
return response ? response[prop] : Reflect.get(...arguments);
},
})
}
}
let b = new B();
b.test ;// "a test";
b.method(); // in the method
var Editor = {};
Editor.Basic = function(obj) {
this.config ={
value: obj
}
};
Editor.Basic.prototype = {
getValue: function() {
return this.config.value;
}
};
Editor.Advanced = function(obj) {
Editor.Basic.call(this, obj);
};
Editor.Advanced.prototype = {
config: {
notValue: !this.config.value
}
};
var extendByPrototype = function(obj1, obj2) {
for (var key in obj2.prototype) {
if (obj2.prototype.hasOwnProperty(key) && obj1.prototype[key] === undefined)
obj1.prototype[key] = obj2.prototype[key];
}
};
extendByPrototype(Editor.Advanced, Editor.Basic);
Is there anyway to get the Editor.Advanced.prototype to extend existing objects (recursively of course) instead of overriding them? (As seen in extendByPrototype)
I know I would check obj1.prototype[key] !== undefined, but I am unsure as what I need to do to extend existing keys in a generic way, without moving the config from Editor.Advanced.prototype to the constructor and using the push function.
The proper way of extending an Object in JavaScript is using Object.create(prototype). Objects created this way will have proper inheritance setup. To get the prototype of any object, you'll use Object.getPrototypeOf(object).
Object.create(prototype) is new in JavaScript 1.8.5. If you're looking for backward compatible, you'll have to use the non-standard way
function extend(child, supertype) {
child.prototype.__proto__ = supertype.prototype;
}
extend(Animal, Lifeform);
extend(Plant, Lifeform);
var anOnion = new Plant();
After that, you can get the prototype object by...
object.contructor.__proto__
More details on __proto__ here: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/proto