sohguanh: Recently, due to the need to learn AJAX coding, I discovered that JavaScript has changed a lot in the last few years–and the different kinds of syntax used to create objects in JavaScript can be mind-boggling!
I come from a C, C++, Visual Basic, Java, Perl and PHP background, and have recently moved on to JavaScript. My knowledge of JavaScript is from the late 90’s era where it was used for simple scripting purposes.
Object Oriented JavaScript: The Questions
For others like myself, a few questions come to mind about Object Oriented (OO) JavaScript, including:
- Is there an Interface concept in JavaScript?
- Is there an abstract class concept in JavaScript?
- Is there a final static variables concept in JavaScript?
- Are there private, protected, public fields/methods in JavaScript?
- Is there a sub-classing and inheritance concept in JavaScript?
- Does JavaScript support multiple inheritances?
- Does JavaScript support templates like C++?
In this JavaScript tutorial we’ll answer these nagging questions and provide you with some sample code to help illustrate our responses.
Object Oriented JavaScript: The Answers
Our answers come from WebDeveloper.com rnd me, who comes from a different background than the member who posed the questions.
First, let me start by saying that a lot of these terms can be ambiguous.
Certain languages implement certain features and patterns in different ways.
I don’t come from a C++/OOP background, which you may find painfully clear below, so bear with me. I’m not sure that JavaScript does 100% of the things that classical languages do. That said, I do know a little bit about OOP, and a lot about JavaScript.
I’ll try to answer as best I can for what I think you’re trying to accomplish.
This type of analysis is just begging for a flame war…for example, I don’t care if JavaScript doesn’t have “official” classes, so long as it is capable of doing the things that “real” classes do.
- Is there an Interface concept in JavaScript?
No, I don’t think so. interfaces are like a type, a user-defined type right?
In one sense, JavaScript has no abstract or composite types, because there’s no way to define a type without making an instance.
On the other hand, the DOM provides several standard collections of methods and properties. You can duplicate, delete, mute, and link methods to/from other objects. As a last resort, you can iterate and duplicate to get the job done.
I might say that constructors and their byproducts are types to themselves. In fact, using a constructor function binds an invisible (non-enumerable) property called constructor to the object. This lets you determine what “type” of object it is.
For soft/literal objects, it’s all about duck-typing and coercion in JavaScript.
- Is there an abstract class concept in JavaScript?
Since objects are soft, and types are dynamic, there’s no need for such a thing. You might say they’re all abstract. Until the next version of ecmaScript comes out, there’s no way to finalize objects.
- Is there a final static variables concept in JavaScript?
One thing at a time.
final: a firefox+webkit extension, const is local:
function check(){
const y={a:1};
y.a=5;
return y;
}
alert(check().a)//===5
but consts aren’t static, they are automatic…you can use assessors to mimic the effect, but on a technical level the answer is no. That said, private variables are safe inside their functions as long as inner-function code doesn’t alter them.
static:
yes, though not how you’d expect. There’s a few ways to do static-y things in JavaScript.
JavaScript can use closure to make things vanish from one perspective, but remain alive from another. You can wrap a function around your code to conceal and preserve variables for other functions:
(function(){
var x=123;
showX=function(){alert(x);}
}());x=99;
showX();//123
In that example, the “123” x will be around as long as the function showX is around. There is no way to alter or delete that specific x, though if it becomes unreachable it will get garbage-collected.
Objects, including functions, can hold properties. Typically, functions are globals, and are thus reachable from anywhere and are permanent. Properties of globals are also permanent and global, so you don’t need to pollute the global namespace with several functions to keep them around.
As a result, the pattern I consider to be the best static is using function names to hold them:
function count(){
return ++count.total;
}; count.total=0;alert([ count(), count(), count(), count(), count() ]);
//shows: 1,2,3,4,5
At the cost of a defining a default, you can define statics internally, which has the added benefit of working in methods:
var o={
counter:
function count(){
count.total=count.total||0
return ++count.total;
}
};alert([ o.counter(), o.counter(), o.counter(),
o.counter(), o.counter(), “Total:”, o.counter.total ]);//shows: 1,2,3,4,5,Total:,5
Note the distinct internal and external function names–that’s important in JavaScript.
- Are there private, protected, public fields/methods concepts in JavaScript?
There are:
- private, public, static, prototype, and privileged methods in all browsers
- private, public, static, and privileged GET properties in all browsers
- private, public, static, and privileged SET properties in IE8+, all recent others
About privileged methods
function Demo(){
function getter(){return private;} //private
var private=555;
this.public=123;
function hi(){alert(“hi”);} // private
this.hello=function(){alert(“hello”);} // public
this.getPrivate=function(){alert(private);} // privileged method
this.invited={valueOf: getter, toString: getter}; // privileged property
Demo.lastBuilt=this; // “static”
}
Demo.prototype.proto=function(){alert(this.public);} //prototype methodvar obj=new Demo();
After running, obj will have the following direct properties:
public, hello, getPrivate, and invited.
In addition, the following are not self-properties, but are available:
o.proto, Demo.lastBuilt
- private, public, static, prototype, and privileged methods in all browsers
- Is there a sub-classing and inheritance concept in JavaScript?
Yes. Objects, including arrays and functions, are accessed by reference, making for dead-simple inheritance/linking from anywhere to anywhere else (within the same window at least).
You don’t even need constructors for this type of inheritance:
var ray=[1,2,3];
var dupe=ray;dupe[1]=”Fred”;
ray[3]=false;alert(ray); //shows: 1,Fred,3,false
There’s also with to temporarily implement the property pool of an object as lexical scope. Function closure can seal in the link created by with, making a permanent bond:
var obj={a:1, b:2, c:3};with(obj){
function adder(){
alert(a+b+c);
}
}//end withadder()//===6
obj.b=10;
adder()//===14
See the next answer for a more classical inheritance pattern using constructors.
Remember that primitives can propagate, but remain frozen; you’ll have to use assessor functions. JavaScript (since 1999) includes two native but read-only assessors for all objects: toString and valueOf. IE8 and later versions of all the other browsers can do GET and SET assessors, which provides a way to do primitive inheritance.
- Does JavaScript support multiple inheritances?
To some extent. You have no explicit control over joins; the closest property always wins. Example:
function Life(){
this.type=”life”
this.alive=true;
}
function Animal(){
this.type=”animal”;
this.age=0;
this.die=function(){this.alive=false;}
}
function Person(){
this.type=”human”;
this.birthday=(new Date).toLocaleDateString();
}
//join the constructors by linking thier prototypes:
Animal.prototype=new Life;
Person.prototype=new Animal;var me= new Person, props=[];
for(property in me){
props.push( property +”:t”+ me[ property ] );
}alert(props.join(“n”));
/* shows:
type: human
birthday: Wednesday, March 24, 2010
age: 0
die: function () {
this.alive = false;
}
alive: true */
- Does JavaScript support templates like C++?
All functions can do something like it:
//making “new ” prefix optional:
function Constructor(args){
if(this.Array==Array){return new Constructor(args);}
this.arg=args;
}
var x= new Constructor(“fred”);//==={ arg=”fred”}
var y= Constructor(“fred”);//==={ arg=”fred”}//overloading/flexible args
function el(id){
if(id.nodeName){return id;} //quack
if(id.splice){return id.map(el);}//quack
return el._ts[id]||(el._ts[id]=document.getElementById(id));
}; el._ts={};the el function recreates document.getElementById()
When used in the same way, el can also accept live elements instead of a string id. This means that el(elm) is guaranteed to give me an element or nothing, even if I don’t know what elm is at design time. It also takes arrays of ids or elements or both mixed.
Note that the el function above requires Array.map that’s built into non-IE browsers and is also available as a seamless drop-in for IE.
Whew, does that answer your questions? Take your shoes off, get comfortable with soft objects and weak types, and enjoy the ride.