How to "Properly" Create a Custom Object in JavaScript

How to properly create a custom object in JavaScript?

There are two models for implementing classes and instances in JavaScript: the prototyping way, and the closure way. Both have advantages and drawbacks, and there are plenty of extended variations. Many programmers and libraries have different approaches and class-handling utility functions to paper over some of the uglier parts of the language.

The result is that in mixed company you will have a mishmash of metaclasses, all behaving slightly differently. What's worse, most JavaScript tutorial material is terrible and serves up some kind of in-between compromise to cover all bases, leaving you very confused. (Probably the author is also confused. JavaScript's object model is very different to most programming languages, and in many places straight-up badly designed.)

Let's start with the prototype way. This is the most JavaScript-native you can get: there is a minimum of overhead code and instanceof will work with instances of this kind of object.

function Shape(x, y) {
this.x= x;
this.y= y;
}

We can add methods to the instance created by new Shape by writing them to the prototype lookup of this constructor function:

Shape.prototype.toString= function() {
return 'Shape at '+this.x+', '+this.y;
};

Now to subclass it, in as much as you can call what JavaScript does subclassing. We do that by completely replacing that weird magic prototype property:

function Circle(x, y, r) {
Shape.call(this, x, y); // invoke the base class's constructor function to take co-ords
this.r= r;
}
Circle.prototype= new Shape();

before adding methods to it:

Circle.prototype.toString= function() {
return 'Circular '+Shape.prototype.toString.call(this)+' with radius '+this.r;
}

This example will work and you will see code like it in many tutorials. But man, that new Shape() is ugly: we're instantiating the base class even though no actual Shape is to be created. It happens to work in this simple case because JavaScript is so sloppy: it allows zero arguments to be passed in, in which case x and y become undefined and are assigned to the prototype's this.x and this.y. If the constructor function were doing anything more complicated, it would fall flat on its face.

So what we need to do is find a way to create a prototype object which contains the methods and other members we want at a class level, without calling the base class's constructor function. To do this we are going to have to start writing helper code. This is the simplest approach I know of:

function subclassOf(base) {
_subclassOf.prototype= base.prototype;
return new _subclassOf();
}
function _subclassOf() {};

This transfers the base class's members in its prototype to a new constructor function which does nothing, then uses that constructor. Now we can write simply:

function Circle(x, y, r) {
Shape.call(this, x, y);
this.r= r;
}
Circle.prototype= subclassOf(Shape);

instead of the new Shape() wrongness. We now have an acceptable set of primitives to built classes.

There are a few refinements and extensions we can consider under this model. For example here is a syntactical-sugar version:

Function.prototype.subclass= function(base) {
var c= Function.prototype.subclass.nonconstructor;
c.prototype= base.prototype;
this.prototype= new c();
};
Function.prototype.subclass.nonconstructor= function() {};

...

function Circle(x, y, r) {
Shape.call(this, x, y);
this.r= r;
}
Circle.subclass(Shape);

Either version has the drawback that the constructor function cannot be inherited, as it is in many languages. So even if your subclass adds nothing to the construction process, it must remember to call the base constructor with whatever arguments the base wanted. This can be slightly automated using apply, but still you have to write out:

function Point() {
Shape.apply(this, arguments);
}
Point.subclass(Shape);

So a common extension is to break out the initialisation stuff into its own function rather than the constructor itself. This function can then inherit from the base just fine:

function Shape() { this._init.apply(this, arguments); }
Shape.prototype._init= function(x, y) {
this.x= x;
this.y= y;
};

function Point() { this._init.apply(this, arguments); }
Point.subclass(Shape);
// no need to write new initialiser for Point!

Now we've just got the same constructor function boilerplate for each class. Maybe we can move that out into its own helper function so we don't have to keep typing it, for example instead of Function.prototype.subclass, turning it round and letting the base class's Function spit out subclasses:

Function.prototype.makeSubclass= function() {
function Class() {
if ('_init' in this)
this._init.apply(this, arguments);
}
Function.prototype.makeSubclass.nonconstructor.prototype= this.prototype;
Class.prototype= new Function.prototype.makeSubclass.nonconstructor();
return Class;
};
Function.prototype.makeSubclass.nonconstructor= function() {};

...

Shape= Object.makeSubclass();
Shape.prototype._init= function(x, y) {
this.x= x;
this.y= y;
};

Point= Shape.makeSubclass();

Circle= Shape.makeSubclass();
Circle.prototype._init= function(x, y, r) {
Shape.prototype._init.call(this, x, y);
this.r= r;
};

...which is starting to look a bit more like other languages, albeit with slightly clumsier syntax. You can sprinkle in a few extra features if you like. Maybe you want makeSubclass to take and remember a class name and provide a default toString using it. Maybe you want to make the constructor detect when it has accidentally been called without the new operator (which would otherwise often result in very annoying debugging):

Function.prototype.makeSubclass= function() {
function Class() {
if (!(this instanceof Class))
throw('Constructor called without "new"');
...

Maybe you want to pass in all the new members and have makeSubclass add them to the prototype, to save you having to write Class.prototype... quite so much. A lot of class systems do that, eg:

Circle= Shape.makeSubclass({
_init: function(x, y, z) {
Shape.prototype._init.call(this, x, y);
this.r= r;
},
...
});

There are a lot of potential features you might consider desirable in an object system and no-one really agrees on one particular formula.


The closure way, then. This avoids the problems of JavaScript's prototype-based inheritance, by not using inheritance at all. Instead:

function Shape(x, y) {
var that= this;

this.x= x;
this.y= y;

this.toString= function() {
return 'Shape at '+that.x+', '+that.y;
};
}

function Circle(x, y, r) {
var that= this;

Shape.call(this, x, y);
this.r= r;

var _baseToString= this.toString;
this.toString= function() {
return 'Circular '+_baseToString(that)+' with radius '+that.r;
};
};

var mycircle= new Circle();

Now every single instance of Shape will have its own copy of the toString method (and any other methods or other class members we add).

The bad thing about every instance having its own copy of each class member is that it's less efficient. If you are dealing with large numbers of subclassed instances, prototypical inheritance may serve you better. Also calling a method of the base class is slightly annoying as you can see: we have to remember what the method was before the subclass constructor overwrote it, or it gets lost.

[Also because there is no inheritance here, the instanceof operator won't work; you would have to provide your own mechanism for class-sniffing if you need it. Whilst you could fiddle the prototype objects in a similar way as with prototype inheritance, it's a bit tricky and not really worth it just to get instanceof working.]

The good thing about every instance having its own method is that the method may then be bound to the specific instance that owns it. This is useful because of JavaScript's weird way of binding this in method calls, which has the upshot that if you detach a method from its owner:

var ts= mycircle.toString;
alert(ts());

then this inside the method won't be the Circle instance as expected (it'll actually be the global window object, causing widespread debugging woe). In reality this typically happens when a method is taken and assigned to a setTimeout, onclick or EventListener in general.

With the prototype way, you have to include a closure for every such assignment:

setTimeout(function() {
mycircle.move(1, 1);
}, 1000);

or, in the future (or now if you hack Function.prototype) you can also do it with function.bind():

setTimeout(mycircle.move.bind(mycircle, 1, 1), 1000);

if your instances are done the closure way, the binding is done for free by the closure over the instance variable (usually called that or self, though personally I would advise against the latter as self already has another, different meaning in JavaScript). You don't get the arguments 1, 1 in the above snippet for free though, so you would still need another closure or a bind() if you need to do that.

There are lots of variants on the closure method too. You may prefer to omit this completely, creating a new that and returning it instead of using the new operator:

function Shape(x, y) {
var that= {};

that.x= x;
that.y= y;

that.toString= function() {
return 'Shape at '+that.x+', '+that.y;
};

return that;
}

function Circle(x, y, r) {
var that= Shape(x, y);

that.r= r;

var _baseToString= that.toString;
that.toString= function() {
return 'Circular '+_baseToString(that)+' with radius '+r;
};

return that;
};

var mycircle= Circle(); // you can include `new` if you want but it won't do anything

Which way is “proper”? Both. Which is “best”? That depends on your situation. FWIW I tend towards prototyping for real JavaScript inheritance when I'm doing strongly OO stuff, and closures for simple throwaway page effects.

But both ways are quite counter-intuitive to most programmers. Both have many potential messy variations. You will meet both (as well as many in-between and generally broken schemes) if you use other people's code/libraries. There is no one generally-accepted answer. Welcome to the wonderful world of JavaScript objects.

[This has been part 94 of Why JavaScript Is Not My Favourite Programming Language.]

How to make custom objects in Javascript?

The first and second options are functionally identical. Most developers choose to use the literal notation because it's a little shorter.

The third option is generally only used when you're looking to create reusable objects (i.e. inheritance). In this case, the function acts as a "constructor" - which is a function that returns a new object instance that can inherit methods and properties defined in the constructor's prototype.

How do you create a method for a custom object in JavaScript?

var newObj = {
met1 : function () {
alert('hello');
}
};

Then, the method can be called like such :

newObj.met1();

Btw, when declaring a new object, use the object literal ({}), not the new Object() constructor.

Custom Object events

Recently, EventTarget got a constructor, so you can actually use it for your JS object – before it was just an interface used only by DOM elements:

class CustomObject extends EventTarget {
constructor() {
super();
this.customEvent = new CustomEvent("afterinit");
}

init() {
this.dispatchEvent(this.customEvent)
}
};

let myObject = new CustomObject();
myObject.addEventListener("afterinit", console.log);
myObject.init();

Unfortunately, the support of EventTarget's constructor is not good enough – see the link above –, and it's a Web API, means supported only in a browser's environment.

how to create a custom object in javascript?

Create myData as an object, then use bracket notation to assign the property values

var myData = {};
$.getJSON(path_url, function (data) {
var len = data.rows.length;
for (var i = 0; i < len; i++) {
var code = data.rows[i].codeid;
var color = data.rows[i].color;
myData[code] = color
}
console.log(myData);
});

how to create a custom object in javascript with length property and add and remove functions

Here is the barebones of a structure I have used before, I have only tested this on the latest browsers - however it isn't using any techniques that should cause a problem. The only possible contention would be prototyping an object with an Array. But I don't see why this wouldn't work in older browsers:

<script>
"use strict";

var ArrayLike = (function(){
/// create a static reference to our constructor so that we can
/// add methods to ArrayLike... if we like.
var _static = function(){
/// store some "private" values, and arrayify our arguments
var _args = Array.prototype.slice.call( arguments ),
_private = { byKey:{}, byIndex:{} },
_public = this;
/// make sure the user used the 'new' keyword.
if ( _public instanceof _static ) {
/// if we have arguments then push them onto ourselves
if ( _args.length ) {
_public.splice.apply(_public,[0,0].concat(_args));
}
/// Now that a new instance has been created, switch in an array
/// prototype ready for the next instance.
_static.prototype = new Array();
/// start adding our methods, bare in mind if you wish to
/// stop any of the native array methods from working you'll
/// have to override them here.
_public.add = function( key, value ){
/// store the keys and indexes as references to themselves.
_private.byKey[key] = _public.length;
_private.byIndex[_public.length] = key;
/// use the inherited push function from the array.
_public.push( value );
}
/// an example function to show how get by key would work.
_public.getByKey = function(key){
if ( (key = _private.byKey[key]) || key === 0 ) {
return _public[key] ? _public[key] : null;
}
}
/// easy removeAll thanks to the array prototype.
_public.removeAll = function(){
_public.length = 0;
}
/// here I leave you to flesh out the methods that you 'want'.
_public.removeByKey = function(){

}
/// I'll give you a clue that keeping your array index in order
/// is going to be a manual process, so whenever you delete you
/// will have to reindex.
_private.reIndex = function(){

}
}
}
/// set-up the prototype as an array ready for creation
_static.prototype = new Array();
/// return the function that will be our constructor
return _static;
})();

</script>

The above is a bit odd from the point of view of a normal constructor, because it is constantly modifying it's prototype, this means the following doesn't work as expected:

var a = new ArrayLike(1,2,3);
alert( a instanceof ArrayLike ); /// alerts FALSE

The benefits of extending from an Array are quite obvious though as you can now treat a like any array - so some of your work is done for you by core JS code. As you are implementing a system that uses keys however, it may be best to override most of the normal array operations so that you can keep a proper track of the keys that are in use in within the structure.

Anyway hope it helps, I've left you to work out the slightly tricky elements of reindexing the array as it should be straight forward with the way the above is setup.

Other enhancements

With regards to setting certain properties to read-only, this is only truly possible in JavaScript 1.8+ - so it wont be backwards compatible to older browsers. You can achieve this using Object.defineProperty(obj, prop, descriptor) as mentioned in Felix Kling's comment. Using this it should be possible to affect things like .length and make them read-only. However, the more locked down you make your code, the less flexible and extensible it will be.

How do you create a property for a custom object in JavaScript?

var newObj = {
myFunc1: function () {
this.greeting = "hello";
},
myFunc2: function () {
alert(this.greeting);
}
};

newObj.myFunc1(); // set the property on newObj
newObj.myFunc2(); // alert the property on newObj

alert(newObj.greeting); // access it directly from the object

Creating/populating Javascript custom object

You cannot access the first object's properties without instantiation, i.e. using the new keyword:

 var myUser = new User() ;
document.write(myUser.id) ;

The second object is an object literal which is accessible without instantiation as it is already instantiated when parsed.

The difference comes into play if you want use prototypical inheritance to create a new object on basis of the old one. Writing an object literal is probably easier to understand and the more appropriate pattern if you have a rather compact code base. However, prototyping comes in handy if you want to create a new object by augmenting an existing object with another object without having to rewrite the object getting augmented:

ipUser.prototype = User ;
ipUser.ip = "128.0.0.1" ;

In your case this difference might not seem striking, but you have to imagine how much redundant code you would get if you would create another object literal for every meager addition to the original object.

Look into the Mozilla Developer Center's page on JavaScript Objects if you have additional questions, it's outlined pretty well: https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference:Global_Objects:Object .

Hth



Related Topics



Leave a reply



Submit