Jump to content

Javascript Proper Object Syntax


Rhuno
 Share

Recommended Posts

Hey all,

 

I'm fairly new to object-oriented javascript and had a quick question about the "right" way to set up an object. Namely, what's the benefit of using prototype versus just creating the function inside the object? Below are some examples:

 

Using prototype

function Rectangle(left, top, right, bottom){    this.left = left;    this.top  = top;    this.right = right;    this.bottom = bottom;			    this.width = right - left;    this.height = bottom - top;}	Rectangle.prototype.getArea = function () { return this.width * this.height; }

 

Not using prototype

function Rectangle(left, top, right, bottom){    this.left = left;    this.top  = top;    this.right = right;    this.bottom = bottom;			    this.width = right - left;    this.height = bottom - top;    this.getArea = function() { return this.width * this.height; }}

As far as usage goes, I don't really see a difference, but I was curious if there was something I'm missing. Any info or advice is appreciated. Thanks!

Link to comment
Share on other sites

In the first example, you are creating one instance of the getArea function. Every Rectangle that you create, will have a reference to that instance.

 

In the second case, every time you create a new instance of Rectangle, you create a new instance of getArea too.

 

That's the theory. In practice, God only knows what each javascript engine does internally to optimize your code :) We've had similar discussions before on this forum (just scroll down a bit to find similar prototype-related topics), and the bottom line is that there is no "right" way. In most cases, it doesn't really matter which way you choose to do it, and in some very special cases, one approach may be better than the other, or viceversa - profiling will help you decide.

Link to comment
Share on other sites

Its mostly memory related.

If you call a method of a object, the engine looks if the method can be found directly on the object.

If not, the endinge continues to look inside the prototype object of the current objects constructor.

 

This means: By storing a method inside the prototype object, all created objects SHARE that same method and its only stored once in memory.

If you assign a method inside the constructor, EVERY created object will have a copy of that same function.

 

Benefit/drawback:

When you overwrite a method inside the prototype object, ALL objects, even the already created ones will use the changed method from that point on.

When you assign methods directly to an object, you would have to overwrite the method on every single created object.

 

 

Another thing to keep in mind:
When you are creating objects and have variables inside the constructor which should be only accessable from the object itself (aka privates),

you CANNOT access them from a method that has been created in the prototype object. Only methods that have been defined inside the constructor

function will be able to access variables that have been defined there.

 

Ask, if you have more questions :)

Link to comment
Share on other sites

To make it a bit more "object oriented", you could revise it such that the internals of Rectangle are private.

I'm sure you'll find several ways to achieve this. Here is a one way.

 

var CreateRectangle = function(left, top, right, bottom){   //private state   var width = right - left;   var height = bottom - top;      var getArea = function () { return width * height; }   return { getArea: getArea };}
Link to comment
Share on other sites

Well, in your example, the use of prototype is completely unnecessary. You are creating a new constructor function with every call of CreateRectangle() [hey, starting with uppercase is wrong here, since its NOT a constructor!].

That constructor is used to create ONE object.

 

When you call the function the next time, a new constructor with a new prototype object is created for a new object.

 

This method wastes the most memory possible :)

Link to comment
Share on other sites

This code is a bit better than the previous one, altough it still does not utilize the usage of prototype methods/properties, which would result in a bigger memory consumption.
I agree that you need to create the method this way, because if you had added the getArea() method to the prototype pool, it would not be able to access the width and height variables defined inside the constructor function.

Let me show you a little variation of your code that I mostly like more - you do not need to pre-define a method before you return the object.

var CreateRectangle = function(left, top, right, bottom){   //private state   var width = right - left;   var height = bottom - top;   return {      getArea: function () {          return width * height;      }   };}

However! This method has a big (or not so big for some of you) drawback:
You cannot test of which type the created object is at a later Point of time, since technically, you created a normal object by returning {}.

Consider the following:
 

var rect;rect = CreateRectangle(10, 10, 20, 20);rect instanceof CreateRectangle => false

You will never be able to tell anywhere in your program - is this really a rectangle?

 

 

Let me give you an example of how I am solving that in most cases:

 

/** * A generic constructor function *  * Notice that there is only one parameter, the function awaits an object. * */function MyObject(params){	//If no object has been passed in, use a empty object.	params = params || {};	//Lets define some public properties which are accessable from	//outside the object, as well as from prototype methods.	this.propertyA = params.propA || 10; //Either use the submitted property "propA", or use 10 as a default value if not given.	this.propertyB = params.propB; // propB can not be defined - in this case this.propertyB would become undefined.	//Check for mandatory properties and throw an error if it is missing.	if(params.propC === void 0){		throw new Error('propC needs to be defined.');	}	//This method is directly defined inside the constructor, since it needs to access the params object that would otherwise	//not be accessable from outside the created object;	//This method is INDIVIDUAL to every instance of MyObject!	this.methodA = function(){		return params.propC;	}}MyObject.prototype = {	//This is a method that does not need to access any "private" (defined inside the constructor) properties, but can work	//by only accessing properties that are part of the "this" scope.	//The method is shared between ALL instances of MyObject and will consume memory only once.	methodA: function(){		return this.propertyA * this.propertyB;	}};

 

In this case, we have it all: private properties, only accessable through a method defined inside the constructor, as well as public properties and prototypal methods. Phew :)

 

Oh, here is why I am mostly using ONE attribute for most functions:

You can shuffle the order of attributes, they are always NAMED and you may leave some optional properties out (since you can shuffle the order as you wish).

 

Compare this two examples of creating a rectangle object:

 

rect = new Rectangle(10, 10, 20, 20);

By looking at that constructor call, you cannot immediately figure out if you have to give x, y, width, hight - or x, y, x2, y2 to create that rectangle.

And thats an easy example!

 

Now look at this:

 

rect = new Rectangle({   x: 10,   y: 10,   width: 20,   height: 20});

Its clear, isn't it? Sure - its more verbose, but also much more readable (imho).

 

There may be a few guys out there that will cry out: "BUT! You won't get autocompletion for that."

Not. True.

 

JSDoc is providing a syntax for that - and most IDEs should be able to parse it:

 

/** * My method description * @param {Object} params * @param {Number} params.x * @param {Number} params.y * @param {Number} params.width * @param {Number} params.height * @param {Bool} [params.invisible] Optional invisible parameter * @return {Rectangle} */ function Rectangle(params){...}

 

But hey - thats just a matter of taste. Luckily Javascript is very flexible to serve everyones flavor.

Just do me a favor: be consistent. Choose your way and stick to it, it greatly improves your coding style.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...