Reputation: 2488
I have a question about how you define your prototype properties. So you don't have to write "MyClass.prototype." to add every property to prototype, people create new object and set it in place of the original.
Like this.
var MyClass = function() {}
MyClass.prototype = {
sayHi : function() {
alert('hi');
}
}
But if you do this, it could cause problems when you try to access constructor from any instance.
var o1 = new MyClass();
alert( o1 instanceof MyClass ); // true
alert( o1.constructor === MyClass ); // false !!!
o1.constructor
would normally point to MyClass, but since the original prototype was changed, it doesn't anymore.
I managed to solve this by MyClass.prototype.constructor = MyClass;
and it works right again.
The question is, what other problems could changing the original prototype cause?
How do You define your prototype properties ?
Upvotes: 3
Views: 267
Reputation: 74204
I usually create "classes" in JavaScript inside out using a simple defclass
function:
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
This function allows me to create classes as follows:
var MyClass = defclass({
constructor: function () {},
sayHi: function () {
alert("hi");
}
});
This method has the following advantages:
constructor
function itself is just another prototype property.constructor
property.For instance:
var o1 = new MyClass;
alert(o1 instanceof MyClass); // true
alert(o1.constructor === MyClass); // true
You can also easily modify defclass
to support inheritance:
function defclass(uber, body) {
var base = uber.prototype;
var prototype = Object.create(base);
var constructor = body.call(prototype, base), prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
You can then use it as follows:
var Rectangle = defclass(Object, function () {
this.constructor = function (width, height) {
this.height = height;
this.width = width;
};
this.area = function () {
return this.width * this.height;
};
});
Inheritance is also just as simple:
var Square = defclass(Rectangle, function (base) {
this.constructor = function (side) {
base.constructor.call(this, side, side);
};
});
Everything works as expected:
var sq = new Square(5);
alert(sq.area()); // 25
alert(sq instanceof Square); // true
alert(sq instanceof Rectangle); // true
alert(sq.constructor === Square); // true
That's all folks.
Upvotes: 2
Reputation: 108490
The constructor
property is just a convenience reference, you can simply reassign it:
MyClass.prototype = {
constructor: MyClass,
sayHi : function() {
alert('hi');
}
}
There shouldn’t be any other "problems" associated with redefining the prototype object, unless of course you are extending another object with predefined prototype properties.
If you want to be brave with your syntax, try using with
. I wouldn‘t recommend it, but it’s still an option if you just want to shorten the syntax:
var MyClass = function() {}
with (MyClass.prototype) {
sayHi = function() {
alert('hi');
}
}
Upvotes: 1
Reputation: 18783
I usually opt for:
function MyClass() {}
MyClass.prototype = {
constructor: MyClass,
foo: function foo() {
// do something
}
};
I realize it overwrites the constructor
property, but it is cleaner to maintain and in practice I haven't noticed any problems in the 10 years I've been writing JavaScript "classes" this way.
The native Object.create method can also be used.
A while ago I created a small JavaScript library to assist in writing classes: Inherit.js
It allows you to create classes like this:
var Point = Object.extend({
includes: [
Mixin1,
Mixin2
],
self: {
// class or "static" methods and properties go here
},
prototype: {
// instance methods and properties go here
}
});
var Point3D = Point.extend({ ... });
It provides support for "mixins" as well, if they are declared like this:
var Mixin = {
includes: [
// Yup, mixins can include mixins too
],
included: function(Klass) {
// Klass is the constructor function that just included this mixin
},
self: {
// class or "static" methods and properties go here
},
prototype: {
// instance methods and properties go here
}
};
Some people would object to duck-typing native classes, but I'm all for it.
Why I went this route:
instanceof
operater still worksUpvotes: 1
Reputation: 887315
You can use a merge/extend function (commonly found in libraries like jQuery or Lodash):
$.extend(MyClass.prototype, { prop: ..., ... });
Upvotes: 1