NOTE: this is my learning notes, some understanding may NOT correct, please correct me if you find any.
There are many tourtorials on Javascript OOP, however not all of them give a very clear picture, here is some notes on Javascript OOP.
- Javascript class is “function”, function body is the “constructor”
function className() {
… // constructor
}
var obj = new className(); // create an instance of className
var result = className(); // call className as a function
…
function classNameAnother(var1, var2) {
…
}
var objAnother = new classNameAnother(param1, param2); //
…
- Create Javascript objects
- Use “new”:
- new className(); // className is defined by “function”
- new Object(); // Object is predefined
- Use literal notation:
var obj = {
propData: 100,
propString: “hello world”,
propArray: ["a", "bbb", "", "jajajaja"],
methodA: function () { … },
methodB: function () {… }
};
- Different ways to define “class” and contruct objects (in different toutorials)
Disfferent tourtorials have different decsription or samples to create javascript objects or rather say an “instance”., sometimes it’s really confusing for javascript OO beginers. I finally spend some time to sort them out, here is the notes.
A. Use literial notation
e.g.
var Me = {
name: “Robert Mao”,
sex: “M”,
say: function() {
alert(”hello world”);
}
};
Me.say(); // alert “hello world”.
var me = new Me(); // ERROR: Me is not a constructor
Me.run = function() {
alert(”I can run”);
}
Me.run(); // alert “I can run”
Me.prototype.runMore = function() {…} // WRONG!!!
This is the fastest way to creat a global object. The literial notation is not a “class”, it can only be used to create one instance.
B. Factory method (by return literial notation)
The factory method is very easy to be confused with the “new” of a “function()”.
The different is, the factory method actually return an object created by literial notation.
Becuase of the closure support in Javascript, it can be used to create some “private” member of a object.
e.g.
function createObject(name)
{
var privateName = name || “I am private name”;
var privateMethod = function () {
return “result of private”;
}
return {
publicName: “I am public name”,
publicMethod: function () {
alert(”privateName is ” + privateName + “, privateMethod called: “+ privateMethod());
}
}
}
var obj = createObject();
obj.publicMethod(); // privateName is I am …
var obj2 = createObject(”robert”);
obj2.publicMethod(); // privateName is robert
C. “new” a “function”
function Person(name) {
var privateName = name || “I am private”;
var privateMethod = function() {
return privateName;
}
this.publicName = “I am public”;
this.publicMethod = function() {
alert(privateName + ” get from public method!”);
}
}
var obj3= new Person(”robert”);
obj3.publicMethod();
Have you noticed the difference between B an C?! They look very similar, but different!
I personally prefer C over B, because this is something look like a “real” class.
—
Different way to create (public) class member
this.method = function() {…} .vs. className.prototype.method = function() {…}
Another part which easy to get confused is the way to define “public” method and members.
X. in the constructor
e.g. (same as the example in above C)
Y. with “prototype”
function Person(name) {
…
}
function.prototype.newMethod = function() {
..
}
In many cases, X, Y have same effect, X will have some benefit of access the “private” members, Y will not able access “private” members defined in the constructor.
However, X is actually add member to this instance only. since it’s from inside the constructor, every time you create an object, the contructor will be called, so such member will add to the new object created.
Y is add member through prototype, so it extend all the instance of such class.
Impact to the class inherit
Javascript’s inherit is tricky…
function A() {
this.method = function() { …}
}
function B() {
var base = A;
base(); // call base constructor
}
B.prototype = new A(); // LINE XXX
var obj = new B();
obj.method(); // ok inherit from class A
Pls. notice that “B.prototype = new A()” is important. because we called “base()” in B’s constructor, so without the line of “B.prototype = new A()”, above sample still work, but following lines will not work:
A.prototype.newMethod = function() {… }
obj.newMethod(); // ok if above line XXX exist, error if it not
Normally, there is no problem using above X or Y to define classes, however let’s consider the method overwrite.
function B() {
this.method = function() {
… // overwrite the “method” defined in base class
}
}
It works without any problem, but what if we need to call the original “method” in the overwrited version?
this.method = function() {
this.__proto__.method.call(this);
… // overwrite the “method” defined in base class
}
It worked but looked ugly… __proto__ is the prototype of a object, we find the original function through the prototype, and then use “call” to invoke it with “this” as context.
If I use prototype to create such method, it will looks more neat:
function A() {…}
A.prototype.method = function() {…}
function B() { …}
B.prototype = new A();
B.prototype.method = function() {
A.prototype.method.call(this); // call old “method” defined in class A
…
}
There are many articles talking about Javascript OOP, unfortunately at first I found the more I read the more I feel confused, the best article I read is http://www.cs.rit.edu/~atk/JavaScript/manuals/jsobj/, it’s a old document written in 1997 (oh, my god, 10 years ago…) but so far the clearest.