A lot or JS developers use prototype style to write (extends) classes (functions) or singleton to have a private scope.
I often use different ways to create my classes (function) and I use prototype only to extend and not to create.
These are some examples:
/** prototype style */
// class Blog
function Blog(){};
// prototype to extend Blog
Blog.prototype = {
getName:function(){
return this.name;
},
setName:function(name){
this.name = name;
},
name:""
};
// how to use Blog class
var myblog = new Blog;
// new Blog() with parenthesis is not useful.
// full prototype style "doesn't accept"
// parameters on constructor
// (or better, it accepts but doesn't use them)
myblog.setName("WebReflection");
// setName is absolutely necessary to set public
// name parameter
/** prototype style */
/** singleton style */
function Blog(name){
return {
getName:function(){
return name;
// name has a global scope
// in this object, private
// for every other external scripts
}
};
};
// how to use this Blog function
var myblog = Blog("WebReflection");
// Singleton style should accept one or more
// arguments on fake constractor.
// myblog is an instanceof Object and
// is not a Blog class (I've not used new to set this var)
The first important difference is that with Singleton you don't need to create setName because a blog name shouldn't be modified from other scripts (in this example).
Then why You should declare public parameter (classVar.name) or public methods (classVar.setName) when a property shouldn't be changable ?
This is a common full prototype style problem, everything is public and everything should be modified from other scripts.
In the other hand, with above Singleton example You don't create an instance of Blog, just recieve everytime a new Object.
With prototype = {something} Your varible will be an instance of className but constructor will be an Object while if You declare every method "manually" variable constructor will be exactly the original function.
function Person1(){};
Person1.prototype = {
getClassName:function(){return "Person1"},
isPerson1:function(){return this instanceof Person1}
};
var p1 = new Person1;
document.write([
p1.getClassName(),
p1.isPerson1(),
p1.constructor,
p1.constructor === Person1
] + "
");
// Person1,true,function Object() { [native code] },false
function Person2(){};
Person2.prototype.getClassName = function(){return "Person1"};
Person2.prototype.isPerson2 = function(){return this instanceof Person2};
var p2 = new Person2;
document.write([
p2.getClassName(),
p2.isPerson2(),
p2.constructor,
p2.constructor === Person2
]);
// Person1,true,function Person2() { },true
For many developers it is a feature, because they think that native code is faster than function eveluation (that should be performed every time) ... however, I've never seen performance differences from prototype style and other styles.
Think that func by func prototype doesn't work as single object too, then I suppose there are a lot of scripts that clones prototype (or extends them) using a for in loop and that these scripts doesn't perform better (if it's true) than others.
This is another way, not native, to have both instanceof class and private scope on object You should do something like that:
function Blog(name){
this.getName = function(){
return name;
// as Singleton, name has
// a global scope inside this
// instance, private for
// every other script
};
};
// You could set private methods too ...
function Blog(name){
// private method, global scope
// inside this instance
function setName(){
selfname = arguments[0] || name;
};
// private variable
var selfname;
this.getName = function(){
setName(name);
return selfname;
};
};
var myblog = new Blog("WebReflection");
// You have an instanceof class Blog with
// a private internal scope and an external one
These kind of class instances are not possible to create with full prototype style and in this case evey instance will not be modified if other scripts changes Blog.prototype.getName with a new function.
function Blog(name){
function setName(){selfname = arguments[0] || name};
var selfname;
this.getName = function(){
setName(name);
return selfname;
};
};
Blog.prototype.getName = function(){
return "prototype doesn't change anything";
};
var myblog = new Blog("WebReflection");
document.write(myblog.getName()); // WebReflection
So this way should be thought as "more secure" than others because created instance will not be affected by prototype changes on constructor or on global Object, however, Singleton should be secure too.
function Blog(){
return {getName:function(){return "WebReflection"}}
};
Blog.prototype.getName = function(){
return "override";
};
Object.prototype.getName = function(){
return "override";
};
var myblog = new Blog;
document.write(myblog.getName()); // WebReflection
// if You don't use new ..
var myblog2 = Blog;
document.write(myblog2.getName()); // override
As I've said, the bad thing of singleton is that resulting variable will not be an instance of used className with or without new before declaration.
Last way, if You need a single object instance in your script, You should use this way too.
Blog = new function(){
// private method
function setName(){
selfname = arguments[0] || name;
};
// private variable
var selfname;
// public method
this.getName = function(){
return selfname;
};
this.setName = function(name){
setName(name);
};
};
Blog.setName("WebReflection");
document.write(Blog.getName());
// what kind of instance ? ... it's an "anonymous secret"
document.write(Blog instanceof Function); // false
document.write(Blog instanceof Blog.constructor);// true
This example is something like Singleton without the possibility to send arguments on constructor (and this one will not be a native Object code).
So this method has a "secret" constructor but You could extend them using Blog.constructor.prototype or extend another class using new Blog.constructor.
This example should be useful when You need a single instance of an anonymous function (a bit harder to be modified from other scripts) but remember that
to create a new instance You need GlobalObj.constructor and that other scripts should change a GlobalObj.construtor with prototype.
Now, this post is just to show different ways to create an "instance of something" ... but at this point I think that:
- if native code constructr is really faster to execute, Singleton should be the better choice (private scope too)
- if speed is important (and native code is really faster) but We don't need a private scope and We need to change every method/property of every className instance, prototype style is the better choice because We can know if a var is instance of a class and not only a generic instanceof Object.
- if extreme speed is not a problem (or native code doesn't perform faster), the best solution should be the simple function, to know both constructor and instanceof ... but We can't change every var in a single line.
- if we need a single anonymous instance, we could use the last example.
The third point limit, the possibility to change every instance of a class, should be solved with a simple Object proto
Object.prototype.syncronize = function(){
for(var key in this.constructor.prototype)
this[key] = this.constructor.prototype[key];
};
function Blog(name){
function setName(){
selfname = arguments[0] || name;
};
var selfname;
this.getName = function(){
setName(name);
return selfname;
};
};
var myblog = new Blog("WebReflection");
document.write([
myblog.constructor === Blog,
myblog instanceof Blog,
myblog.getName()
]);
// true,true,WebReflection
Blog.prototype.getName = function(){
return "override";
};
document.write([
myblog.constructor === Blog,
myblog instanceof Blog,
myblog.getName()
]);
// true,true,WebReflection
myblog.syncronize();
document.write([
myblog.constructor === Blog,
myblog instanceof Blog,
myblog.getName()
]);
// true,true,override
So, wich way do You like and Why ?