拿物件導向的 Java 來比較一下,倒是一個不錯的出發點。
Java 用的是 class(類別),Javascript 用的是 prototype(原型)。
Java 是靜態的,Javascript 是動態的。
Java 有多型與繼承,Javascript 也有。
多才多藝的 function
Javascript 的 function 有很多種用法,可以是一般的 fucntion,也可以是 constructor(建構函式)。
function hello(name) { return 'Hello ' + name; } hello('Neil'); // 直接呼叫 function Book(title, author) { this.title = title; // instance 變數 this.author = author; // instance 變數 } var b = new Book('Javascript', 'Rhino'); // 透過 new 呼叫hello() 是最常見的用法,而透過 new 呼叫的話,就變成是 constructor 了。
prototype
變身 constructor 以後,除了 function 裡可以用 this 將變數存下來以外,最重要的是多了一個 prototype 屬性,從這裡就開始進入 Javascript 的 prototype 世界了。
可以透過這個 prototype 定義共用的 function(我把這種 function 叫做 prototype function),就像是 Java class 裡的 method,在這些 function 裡可以透過 this 存取到 instance 變數或者其他 prototype function。
Book.prototype.toString = function() { return this.title + "/" + this.author; // 存取在 constructor 裡定義的 instance 變數 } b.toString(); // Javascript/Rhino Book.prototype.view = function() { return this.toString(); // 存取其他 prototype function } b.view(); // Javascript/Rhino
動態語言
Javascript 與 Java 很大不同的一點是,Javascript 是動態語言,可以邊跑邊組裝。try { b.print(); } catch (e) { console.log(e); // TypeError: b.print is not a function {stack: (...), message: "b.print is not a function"} } Book.prototype.print = function() { return '[' + this.title + '] written by ' + this.author; }; console.log(b.print()); // [Javascript] written by Rhino即使在 b 已經產生之後,再去修改 Book.prototype,b 馬上得到修改後的結果。
其實這樣講有點失真,正確的講法應該是 Javascript 在查找屬性或 function 時,是從 instance 開始找起,如果沒找到就往 prototype 找去,本身的 prototype 如果還是沒找到,就會往「Super class」的 prototype 找去,這裡我還不知道怎麼稱呼這個角色,就先借用 Java 的用詞,若以這裡的 Book 為例,就是指 Object.prototype,最常見的就是 toString() 與 valueOf() 這兩個來自 Object.prototype 的 function。
可以請瀏覽器顯靈給我們瞧瞧這神秘的過程。
console.log(b);
Book 的 prototype 是 Book.prototype,而 Book.prototype 的 prototype 就是 Object.prototype。
多型與繼承
從這裡就可以看到 Javascript 的物件本質是有繼承的,而且也可以是多型。console.log(b instanceof Book); // true console.log(b instanceof Object); // true
接著來看看怎麼從 instance 取得 prototype。
console.log(b.prototype); // undefined console.log(Object.getPrototypeOf(b) == Book.prototype); // true console.log(b.__proto__ == Book.prototype); // trueprototype 屬性只能從 constructor Book 取得,不能從 instance b 取得,在 Javascript 1.5 以前可以用非標準的 __proto__ 屬性取得,在 Javascript 1.5 以後,就可以用標準的 Object.getPrototypeOf() 取得。
最後用 Java 的角度來描述一下 Javascript 的 prototype,Javascript 裡雖然沒有類別(class),但有類似的觀念,就是一個用來存放 instance 變數的 constructor function 加上用來設定共用 method 的 prototype 屬性。
---
雖然一般人不會用 OOP 的方法來要求或使用 Javascript,這邊只是純粹好奇而已,那 Javascript 能實做出 Java 的 static method 和常數嗎?從前面的 Object.getPrototypeOf() 可以知道 static method 的確存在,只是我還不知道怎麼實做。
從前面的顯靈過程往下挖,的確可以找到一堆 static method。
改天再來看看怎麼做了!
---
---
---
沒有留言:
張貼留言