Reputation: 3384
I am working on implementing a simple Class in JavaScript. I know there are many great libraries out there that already does this. However, my intent is to understand the JavaScript prototype model better. Anyhow, I wrote the following. It is working as far as I can tell but with one catch I will describe later:
function Class(constructor,prototypeObj){
var c = constructor;
c.create = function(){
//var o = new constructor();
var o = Object.create(c.prototype);
c.apply(o,arguments);
return o;
};
c.prototype = prototypeObj;
return c;
}
var Animal = Class(
function Animal(life){
this.life = life;
},
{
type: "animal",
sayLife: function(){
console.log(this.life);
}
}
);
var o = Animal.create(15);
console.log(o instanceof Animal); // True
console.log(o.sayLife()); // 15
console.log(o.type); // "animal"
However, my problem is that when I input in o (for the instance) in the console; it prints
Object {life: 15, type: "animal", sayLife: function}life: 15 __proto__: Object
But I would like it to be
Animal {life: 15, type: "animal", sayLife: function}life: 15 __proto__: Object
If I change line 4 and 5 in the constructor.create method to use new constructor() instead of Object.create(constructor.prototype), I get the desired behaviour but then I have issues passing in arguments to the constructor when initializing a new object. If I return a function other than the constructor passed into the class function, then the objects names would not be Animal but something else like "Object" or "F".
So my question is is there any way to implement the Class function such that the instances of the Class always share the same name as the constructor function?
Upvotes: 2
Views: 70
Reputation: 74234
Did you know that the constructor
function is not really a special function? It's just like any other method on the prototype. So you don't need to treat it any differently from other prototype methods. This is what I usually do:
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
This allows me to create constructors as follows:
var Animal = defclass({
constructor: function Animal(life) { // note that I named the constructor
this.life = life;
},
sayLife: function () {
console.log(this.life);
},
type: "animal"
});
Then we can use it as follows:
var o = new Animal(15);
console.log(o instanceof Animal); // true
console.log(o.sayLife()); // 15
console.log(o.type); // "animal"
The reason your code didn't work as expected was because you forgot to reset the constructor
property on the prototype
. However using my method, since the constructor
method is already a property of prototype
, you don't have to do anything else.
For more information about prototypal inheritance see the following question:
JavaScript inheritance and the constructor property
Upvotes: 1
Reputation: 239623
function Class(constructor, prototypeObj) {
var c = constructor;
c.create = function() {
//var o = new constructor();
var o = Object.create(c.prototype);
c.apply(o, arguments);
return o;
};
c.prototype = prototypeObj;
c.prototype.constructor = constructor;
return c;
}
var Animal = Class(
function Animal(life) {
this.life = life;
}, {
type: "animal",
sayLife: function() {
console.log(this.life);
}
}
);
var o = Animal.create(15);
console.log(o);
If you simply want to change the type of the Object being printed in the console, then you need to adjust the constructor function's prototype property's constructor
property, like this
c.prototype = prototypeObj;
c.prototype.constructor = constructor;
return c;
Upvotes: 2
Reputation: 3327
You might want to use Object.create()
The Object.create() method creates a new object with the specified prototype object and properties.
This allows you to fully configure an object when creating, including the possibility of specifiying any constructor:
var o = Object.create(Animal.prototype,{
constructor:{
value: Animal
}
})
Edit:
See @dfsq 's answer and the comments below for an even simpler solution.
Upvotes: 1