2010年9月15日 星期三

Javascript 的 prototype 特性與使用方法

一般我們在 javascript 中使用這種方式進行類別定義與活化類別
// 以 function 為建構子
function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}

//然後活化類別
var p = new Person("Dino", "Wang");


如你所見這樣的類別並不具有"成員函式",所以當你需要成員函式時你可能會手動繫結上去
// 附加一個匿名函式到 p 實體
p.fullName = function () { 
  return this.firstName + " " + this.lastName; 
}


這樣的問題是,每一個被活化的類別都需要進行一次上述動作(以下稱為成員繫結),如果你這類別會產生多個物件,就會造成匿名函式重複產生的問題(浪費記憶體)


正確而有效的做法是進行 prototype 宣告,將類別定義修改如下
function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}
Person.prototype.fullName = function () { return this.firstName + " " + this.lastName; }

var p = new Person("Dino", "Wang");
var fullName = p.fullName();   // Workable!

此後每一個被活化的 Person 類別都自動具有 fullName 成員函式,不需要額外進行繫結

值得一提的是,javascript 允許你對已經定義過的類別,附加成員,還且還會一併讓已經被活化的物件也具有這份"原型",例如:
// 你可以為 String 擴充 trim() 功能
String.prototype.trim = function () { return this.replace(/^\s*|\s*$/g, ""); }

var name = " Dino ".trim();

// 為 Array 增加 append() 以模擬出 .NET Framework 效率較高的 StringBuilder 
Array.prototype.append = function (val) { this.push(val); return this; }

var sb = [].append("1").append("2").append("3").join(" ");


常用的 javascript 版本(1.2) 沒有常見的 class 的定義方式,因為它是 prototype-oriented


NOTE: 關於 javascript 對比到一般物件導向語言的 繼承、類別成員、靜態成員 的方式,簡單整理如下:
// Constructor
function SuperClass() {}

// SuperClass behaviors
SuperClass.prototype.toString = function () {
  return "I'm super class.";
}

// Constructor
function UserClass() {
  SuperClass.apply(this, arguments);      // Call constructor, like C#  base(...)
}

// Inheritance
UserClass.prototype = new SuperClass;

// Data member
UserClass.prototype.property1 = 0;
UserClass.prototype.property2 = 0;

// Member function
UserClass.prototype.method1 = function () {}
UserClass.prototype.method2 = function () {}

// Static data member
UserClass.instances = 0;
UserClass.cache = [];

// Static member function
UserClass.staticMethod1 = function () {}
UserClass.staticMethod2 = function () {} 

沒有留言: