Recommended Posts

I am attempting to learn how to create classes in Javascript & how to perform object inheritance. I have followed some tutorials but I am not sure if my code is correct.

- Am I creating public functions & attributes correctly? If not, what should I change?
- Am I creating privileged functions & attributes correctly? If not, what should I change?
- Am I creating private functions & attributes correctly? If not, what should I change?
- Am I overriding functions correctly?
- Am I performing inheritance correctly?
- If theres anything wrong can you show me how the code should be?

/* Privileged: */
// Will an object that inherits from this class be able to override the following functions?
// Or do I have to make these functions public in order to override them?
this.toString = function()
{
var s = "";
for (var attrib in attributeMap)
{
s += attrib + ": " + attributeMap[attrib] + ", ";
}
return s;
}

Share this post

Link to post

Share on other sites

You're doing some strange stuff here, and it would be good for you to study JavaScript some more. In my experience, it is difficult to learn JavaScript from tutorials... a good book works much better. David Flanagan's "Javascript: The Definitive Guide, 6th Edition" is the best and most comprehensive if you have some programming experience.

JavaScript supports a model of inheritance that is based on prototypes, not classes. You can emulate the concept of classes in JavaScript, but it's a silly thing to do. Prototypal inheritance is the more expressive paradigm. If you take time to learn the paradigm, you can avoid the painful process of coercing JavaScript to behave like some other (usually less expressive) language.

JavaScript objects are created with object literals or constructor functions. In your example, BaseClass is a constructor function. It performs initialization by setting properties on 'this', which refers to the newly constructed object (and thus is the return value of the constructor function). By convention, the only variables/properties you should capitalize in JavaScript are those that refer to constructor functions such as BaseClass. This lets you know whether or not you need to call them with the 'new' operator.

Note that this constructor function (BaseClass in your example) is the "default constructor". You should perform all initialization here, and not in some other function. Setting the 'this.constructor' property will not create a default constructor and will not work as you intend.

If you've seen people setting 'constructor' properties on tutorials and such, it probably comes from this little JS detail (that you should probably ignore early on -- it's not typically very useful and risks confusing things): Prototype objects have (by default) a 'constructor' property that refers to their associated constructor function. This means that 'BaseClass.prototype.constructor' refers to 'BaseClass' (unless you replace BaseClass.prototype with a different object), and that all objects created with BaseClass inherit this same 'constructor' property that points to BaseClass.

Setting properties on 'this' within a constructor function is similar to creating instance variables in classical languages: each created object will have its own version of the property. Setting properties on the 'prototype' property of a constructor function (BaseClass.prototype in your example) makes the same exact properties available on all objects created with the constructor (sort of like static variables in languages with classical inheritance, but they behave a little different). If you reset an inherited property on any created object, the new property value will shadow the prototype value. You can use the delete operator to later get rid of this shadowing value and make the prototype value visible again. Note that if the prototype value is a reference type, and you make changes to the object being referred to (instead of changing what is being referred to), then the changes will be applied to the value stored on the prototype (instead of the instance) and therefore will affect all objects of this "type".

Usually you will set properties on a constructor's prototype outside of the constructor function, not inside of it. Setting these inside the constructor redefines the prototype properties each time an object is constructed, which is not typically what you want.

To inherit, you 'call' or 'apply' the super-constructor on the 'this' object of the sub-constructor:
function ChildClass () {BaseClass.call (this);} // you would also want to do other initialization of ChildClass here

then set ChildClass's prototype to inherit from BaseClass's prototype. In EcmaScript 5 you could do:
ChildClass.prototype = Object.create (BaseClass.prototype);

and then add any other shared properties to ChildClass.prototype.

Note that the way I did this does not uphold ChildClass.prototype's 'constructor' property. If you're using these, you'll want to set it:
ChildClass.prototype.constructor = ChildClass;

I don't have time to explain how to have private instance variables right now, but I can point you in the right direction: study JavaScript scope, closures, and anonymous functions.

It's a common misconception that JavaScript is some sort of "light" programming language that you don't need to study specifically. A lot of people assume that they're ready to program JavaScript simply because they know some other, different language really well. Then they run into problems and conclude that "JS sucks!". Really it is one of the nicer "popular" languages out there, but you have to show it respect and give it the time it needs. JavaScript has many things in common with functional programming languages like LISP or Scheme. If you only know languages along the lines of C++ or Java, you'll have a bit of learning to do. Have fun with it!