-
Notifications
You must be signed in to change notification settings - Fork 3
simply class style
In Javascript, there is no keyword class
, so how we can define a class ? Here goes examples.
/* Anim class */
var Anim = function(name) {
this.name = name;
};
/* declare methods */
Anim.prototype.start = function() {
console.log("Anim object " + this.name + " starts");
};
Anim.prototype.stop = function() {
console.log("Anim object " + this.name + " stops");
};
/* Usage */
var anim = new Anim("robot");
anim.start();
anim.stop();
It is how class is defined in Javascript. If it is Java, C++ or Python, you may have those little boxes in your head how class and object are located and connected with each other. So how do those boxes look like ? It is a piece of simple code. However, Javascript does a lot of work behind the scene. Let's chop this small piece of code into micro pieces.
/* Anim class */
var Anim = function(name) {
this.name = name;
};
/* What is Anim */
console.log(Anim);
/*
Output: [Function]
It is an anonymous function
*/
/* So it is an instance of Function ? */
console.log(Anim instanceof Function);
/*
Output: true
*/
/*
How Js knows Anim is an instance of Function, Anim has some attribute called type or class?
No, it doesn't, but it has something similar, called prototype chain, which is used to inherite
class in Javascript
*/
console.log(Anim.__proto__===Function.prototype);
/*
Output: true
When variable Anim is assigned, JS provides it an attribute called __proto__, which is used to
define its class. In this case, Anim is an instance of Function.
*/
/*
So Anim is an instance of Function, well, what does it have from Function ?
*/
var AnimOwnProperties = Object.getOwnPropertyNames(Anim);
for(var i=0, length=AnimOwnProperties.length; i<length; i++) {
console.log(AnimOwnProperties[i]+ " : " + Anim[AnimOwnProperties[i]]);
}
/*
Output
caller : null
length : 1
prototype : [object Object]
arguments : null
name :
Explain
caller: the one which calls Anim
length: the length of arguments defined in Anim
prototype: the behavior of Anim's instances should have
arguments: the arguments of Anim when it is called
name: the name of function which defines Anim. In this case, anonymous, so empty
*/
/*
What is in prototype ?
*/
var prototypeOfAnim = Object.getOwnPropertyNames(Anim.prototype);
for(var i=0, length=prototypeOfAnim.length; i<length; i++) {
console.log(prototypeOfAnim[i]+ " : " + Anim[prototypeOfAnim[i]]);
}
/*
Output
constructor : function (name) {
this.name = name;
}
WoW, So it is the definition of Anim ?
*/
console.log(Anim===Anim.prototype.constructor);
/*
Output: true
Yes, Anim.prototype.constructor is referred to Anim itself.
*/
/* declare methods */
Anim.prototype.start = function() {
console.log("Anim object " + this.name + " starts");
};
Anim.prototype.stop = function() {
console.log("Anim object " + this.name + " stops");
};
/*
There are more stuff defined in Anim.prototype. Let's have a look.
*/
prototypeOfAnim = Object.getOwnPropertyNames(Anim.prototype);
for(var i=0, length=prototypeOfAnim.length; i<length; i++) {
console.log(prototypeOfAnim[i]+ " : " + Anim.prototype[prototypeOfAnim[i]]);
}
/*
Output
constructor : function (name) {
this.name = name;
}
stop : function () {
console.log("Anim object " + this.name + " stops");
}
start : function () {
console.log("Anim object " + this.name + " starts");
}
*/
/* Usage */
var robot = new Anim("robot");
var space = new Anim("space");
/*
So robot and space are instances of Anim, I can prove it by
*/
console.log(robot.__proto__===Anim.prototype);
console.log(space.__proto__===Anim.prototype);
/*
Output:
true
true
So they share the same class space, then they should just have one copy for those methods
in class Anim.
*/
console.log(robot.__proto__===space.__proto__);
console.log(space.start===robot.start);
console.log(space.start===Anim.prototype.start);
/*
Output:
true
true
true
*/
/*
Which more attributes or methods do space and robot have ?
*/
prototypeOfspace = Object.getOwnPropertyNames(space);
for(var i=0, length=prototypeOfspace.length; i<length; i++) {
console.log(prototypeOfspace[i]+ " : " + space[prototypeOfspace[i]]);
}
/*
Output
name : space
*/
robot.start();
robot.stop();
From this example, we can conclue following points:
- Class is defined as a function, which is also its constructor. Let's name the class
X
. - Attributes and Methods in Class is defined in
X.prototype
, including constructor method. -
instance_x = new X(constructor_arguments) => instance_x.__proto__ === X.prototype
, which means, instance_x can call all the methods in X.prototype. That is a prototype chain inheritance in Javascript. - The joke is there is NO Class in Javascript, only object instantiation.
X
,instance_x
are actually objects. The prototype chain defines their relationship. Their own properties can be defined directly by
X.property_name = X_property_value
instance_x.property_name = instance_x_property_value
- When you call
instance_x.something
:-
instance_x
searches its own properties first, whether there existssomething
. You can check its own properties byObject.getOwnPropertyNames(instance_x)
; -
instance_x
searches itsinstance_x.__proto__
ifsomething
does not exist in the first step.instance_x.__proto__
is referred to instance_x's superclass, in this case,X.prototype
; - If
instance_x
can not find thesomething
, it will throw an error, otherwise execute it.
-
Let's be creative to have some fun with the method define in class. In the previous example, since we know the fact
Anim.__proto__===Function.prototype
, which means Anim can call any methods defined in Function.prototype. Then we define a method called method
in Function.prototype in order to create methods in Anim.
/* Add a method to the Function object that can be used to declare methods */
Function.prototype.method = function(name, fn) {
this.prototype[name] = fn;
}
/* Anim class */
var Anim = function(name) {
this.name = name;
};
console.log(Object.getOwnPropertyNames(Anim.prototype)); // [ 'constructor' ]
Anim.method("start", function() {
console.log("Anim object " + this.name + " starts");
}
);
Anim.method("stop", function() {
console.log("Anim object " + this.name + " stops");
}
);
console.log(Object.getOwnPropertyNames(Anim.prototype)); // [ 'stop', 'constructor', 'start' ]
/* Usage */
var anim = new Anim("robot");
anim.start();
anim.stop();
Let's play a chain design pattern on this example a bit.( who doesn't like sequence ? :D Concurrency ? )
Function.prototype.method = function(name, fn) {
this.prototype[name] = fn;
return this; /* MAKE IT CHAIN */
};
/* Define Anim */
var Anim = function(name) {
this.name = name;
};
Anim.
method('start', function() {
console.log(this.name + " starts");
}).
method('stop', function() {
console.log(this.name + ' stops');
});
var anim = new Anim("hubot");
anim.start();
anim.stop();