在 Programming 圈子混久了,常常聽到人家說 Javascript 是一隻沒有 OO 的語言,又或者說 Javascript 的 OO 很弱,我想,這大概是因為大家都習慣了用 Class 來實作 OO,認為這個世界上有 Class 才算是寫 OO。要探討這個問題,先要想想 OO 到底是什麼。本文除了分享我對 Javascript OO 的看法外,亦會介紹一下在 Javascript 中編寫 Object 的幾種方法。
維基給 OO 下的定義:
concepts as "objects" that have data fields (attributes that describe the object) and associated procedures known as methods
如果只是根據這個標準的話,那很明顯 Javascript 可以輕鬆過關,Javascript 最基本最簡單的 Object 寫法就可以有 data fields 和 procedures。
好吧,那嚴謹一點,一般 OO 語言有什麼特徵?我想主要有三:Inheritance、Polymorphism、Encapsulation,來看看 Javascript 如何做到這幾項。
Inheritance,在 Javascript 中如何繼承一個 class 呢?答案是使用 Object 裏的 prototype 屬性!Javascript 是一種 prototype-based language,prototype-based language 的特徵是透過複製現有的 object 來重用代碼,注意,是 object 而不是 class,這就是 prototype-based OO 跟 class-based OO 最大的分別了。以下是一個繼承 object 的示範:
var base = {
test: function (){
$("#msg").html($("#msg").html() + "test<br/>");
}
};
base.test2 = function (){
$("#msg").html($("#msg").html() + "test2<br/>");
};
function sub(){
}
sub.prototype = base;
var subObj = new sub();
subObj.test();
subObj.test2();
http://jsfiddle.net/dukeland/FZeZY/
這有什麼好處呢?就是令 Javascript 更加動態,可以在 runtime 時加上 function,不用在 compile time 就定死一個 class 有什麼行為。
Polymorphism,因為 Javascript 的動態,它天生就是多態的,在使用一個 object 的 method 時,Javascript 會根據你最後一次的改變來決定使用哪個 method。
function Shape(){
}
Shape.prototype.sayHello = function (){
//to be implemented
};
function Rect(){
}
Rect.prototype = new Shape();
Rect.prototype.sayHello = function (){
$("#msg").html($("#msg").html() + "I am Rect
");
};
function Circle(){
}
Circle.prototype = new Shape();
Circle.prototype.sayHello = function (){
$("#msg").html($("#msg").html() + "I am Circle
");
};
var shapes = [new Rect(), new Circle(), new Rect()];
for (var i = 0, l = shapes.length; i < l; i++){
shapes[i].sayHello();
}
http://jsfiddle.net/dukeland/c7B7Q/
Encapsulation,其核心思想是只“顯示”必需的東西。在 class-based OO 我們是透過 public private 等關鍵字來控制一個 method 的存取權,那在 Javascript 中我們如何做到呢?其實 Javascript 是一個擁有 first-class function 的語言,所謂 first-class function 的意思就是這隻語言容許 function 作為一般變數般處理,例如你可以把 function 當成 argument 般傳到另一個 function 使用,亦可以當成變數般儲存。憑著這個特異功能,我們就可以編寫 private method 了。
function cls(){
var privateMethod = function (){
$("#msg").html($("#msg").html() + "calling private method
");
}
return {
publicMethod: function (){
$("#msg").html($("#msg").html() + "calling public method
");
privateMethod();
}
}
}
var obj = new cls();
obj.publicMethod();
http://jsfiddle.net/dukeland/Cjhdf/
Javascript 其實是一隻擁有完整 OO 的語言,除了因為它的變數類型都是 object 之外,亦因為他擁有上述三大 OO 特性:Inheritance、Polymorphism 及 Encapsulation。因此,下次再有人說 Javascript 不是一隻 OO 語言的話,你就可以大大聲跟他說:是你不懂得 Javascript 是什麼,是你不懂得何謂 OO!
http://dukeland.hk/2013/02/18/javascript-object-oriented-programming/