Jump to content
  • Advertisement
Sign in to follow this  
gretty

Javascript Attempt at making classes & performing inheritance: is it correct?

This topic is 2536 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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?

Heres my simple code that creates a base class then a child class:

/* Base Object Class */
function BaseClass( /*string*/ objType )
{
/* Public: */
this.name = "blah";

BaseClass.prototype.getName = function()
{
return this.name;
}

BaseClass.prototype.setName = function( newName )
{
var oldName = this.name;
this.name = newName;

return oldName;
}


/* Private: */
var attributeMap = {};

this.constructor = function()
{
// this objects default constructor. Is this correct?
attributeMap["type"] = objType;
attributeMap["uniqueID"] = "Base"+(++INSTANCE_COUNT);
}


/* 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;
}

this.getType = function()
{
return attributeMap["type"];
}

this.renderObject = function()
{
// TODO: render object on HTML5 canvas
}

this.parseXMLNode = function( /*XML Node*/ nodeXML, /*string*/ objType )
{
var attribs = nodeXML.attributes;

for (var i=0; i<attribs.length; i++)
{
attributeMap[ attribs.nodeName ] = attribs.nodeValue;
}

// store children
if ( nodeXML.hasChildNodes() )
{
attributeMap["children"] = nodeXML.childNodes;
}

reformatObjectInnerHTML();
}

}


// Static Variables //
BaseObject.INSTANCE_COUNT = 0;


// My Child Class //
ChildClass.prototype = new BaseObject( objType ); // make ChildClass inherit from BaseClass
ChildClass.prototype.constructor = function(ObjType) // Make the ChildClass call the BaseClass constructor
{
BaseObject.prototype.constructor.call(this, objType);
}

function ChildClass( /*string*/ objType )
{
/* Privileged: */
// Attempt to override BaseClass function renderObject()
this.renderObject = function()
{
alert("ChildClass::renderObject();");
// Does this override the BaseClass renderObject() function?
}
}


Share this post


Link to post
Share on other sites
Advertisement
Heres a couple quick things I noticed skimming over it:

1. You can actually have setters and getters, instead of setName(). In the prototype of an object you can do this:


Parent.prototype={
get Name() {
return this.name;
},

set Name( val ) {
this.name = val;
}
}



then you can call get an set the name with parent.Name or set it with parent.Name = "asdf";


You can also call the parent prototypes constructor with:

Parent.call(this, -arguments-);

inside of the childs constructor. Not really required, but can make it easier to follow along.






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!

Share this post


Link to post
Share on other sites
Thanks for the detailed post. Its alot to take in right now but I understand I need to not treat javascript as an OO langauge like C++. Going to go apply some stuff to a new prototype.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!