原型擴展 String.prototype.trim = function String$trim() {
if (arguments.length !== 0 ) throw Error.parameterCount(); return this .replace( / ^\s+|\s+$ / g, '' ); }
function Person(firstName, lastName, age)
{ // 私有變量: var _firstName = firstName; var _lastName = lastName; // 公共變量: this .age = age; // 方法: this .getName = function () { return (firstName + " " + lastName); }; this .SayHello = function () { alert( " Hello, I'm " + firstName + " " + lastName); }; }; var BillGates = new Person( " Bill " , " Gates " , 53 ); var SteveJobs = new Person( " Steve " , " Jobs " , 53 ); BillGates.SayHello(); SteveJobs.SayHello(); alert(BillGates.getName() + " " + BillGates.age); alert(BillGates.firstName); // 這里不能訪問到私有變量
// 定義構(gòu)造函數(shù)
function Person(name) { this .name = name; // 在構(gòu)造函數(shù)中定義成員 }; // 方法定義到構(gòu)造函數(shù)的prototype上 Person.prototype.SayHello = function () { alert( " Hello, I'm " + this .name); }; // 子類構(gòu)造函數(shù) function Employee(name, salary) { Person.call( this , name); // 調(diào)用上層構(gòu)造函數(shù) this .salary = salary; // 擴展的成員 }; // 子類構(gòu)造函數(shù)首先需要用上層構(gòu)造函數(shù)來建立prototype對象,實現(xiàn)繼承的概念 Employee.prototype = new Person() // 只需要其prototype的方法,此對象的成員沒有任何意義! // 子類方法也定義到構(gòu)造函數(shù)之上 Employee.prototype.ShowMeTheMoney = function () { alert( this .name + " $ " + this .salary); }; var BillGates = new Person( " Bill Gates " ); BillGates.SayHello(); var SteveJobs = new Employee( " Steve Jobs " , 1234 ); SteveJobs.SayHello(); SteveJobs.ShowMeTheMoney(); 原型類模型雖然不能模擬真正的私有變量,而且也要分兩部分來定義類,顯得不怎么“優(yōu)雅”。不過,對象間的方法是共享的,不會遇到垃圾回收問題,而且性能優(yōu)于“閉包”模型。正所謂“有失必有得”嘛。 在原型模型中,為了實現(xiàn)類繼承,必須首先將子類構(gòu)造函數(shù)的prototype設置為一個父類的對象實例。創(chuàng)建這個父類對象實例的目的就是為了構(gòu)成原型鏈,以起到共享上層原型方法作用。但創(chuàng)建這個實例對象時,上層構(gòu)造函數(shù)也會給它設置對象成員,這些對象成員對于繼承來說是沒有意義的。雖然,我們也沒有給構(gòu)造函數(shù)傳遞參數(shù),但確實創(chuàng)建了若干沒有用的成員,盡管其值是undefined,這也是一種浪費啊。 var Person = // 定義一個對象來作為原型類
{ Create: function (name, age) // 這個當構(gòu)造函數(shù) { this .name = name; this .age = age; }, SayHello: function () // 定義方法 { alert( " Hello, I'm " + this .name); }, HowOld: function () // 定義方法 { alert( this .name + " is " + this .age + " years old. " ); } }; 這個JSON形式的寫法多么象一個C#的類啊!既有構(gòu)造函數(shù),又有各種方法。如果可以用某種形式來創(chuàng)建對象,并將對象的內(nèi)置的原型設置為上面這個“類”對象,不就相當于創(chuàng)建該類的對象了嗎? function anyfunc(){}; // 定義一個函數(shù)軀殼
anyfunc.prototype = Person; // 將原型對象放到中轉(zhuǎn)站prototype var BillGates = new anyfunc(); // 新建對象的內(nèi)置原型將是我們期望的原型對象 不過,這個anyfunc函數(shù)只是一個軀殼,在使用過這個軀殼之后它就成了多余的東西了,而且這和直接使用構(gòu)造函數(shù)來創(chuàng)建對象也沒啥不同,有點不爽。 function New(aClass, aParams) // 通用創(chuàng)建函數(shù)
{ function new_() // 定義臨時的中轉(zhuǎn)函數(shù)殼 { aClass.Create.apply( this , aParams); // 調(diào)用原型中定義的的構(gòu)造函數(shù),中轉(zhuǎn)構(gòu)造邏輯及構(gòu)造參數(shù) }; new_.prototype = aClass; // 準備中轉(zhuǎn)原型對象 return new new_(); // 返回建立最終建立的對象 }; var Person = // 定義的類 { Create: function (name, age) { this .name = name; this .age = age; }, SayHello: function () { alert( " Hello, I'm " + this .name); }, HowOld: function () { alert( this .name + " is " + this .age + " years old. " ); } }; var BillGates = New(Person, [ " Bill Gates " , 53 ]); // 調(diào)用通用函數(shù)創(chuàng)建對象,并以數(shù)組形式傳遞構(gòu)造參數(shù) BillGates.SayHello(); BillGates.HowOld(); alert(BillGates.constructor == Object); // 輸出:true 這里的通用函數(shù)New()就是一個“語法甘露”!這個語法甘露不但中轉(zhuǎn)了原型對象,還中轉(zhuǎn)了構(gòu)造函數(shù)邏輯及構(gòu)造參數(shù)。 // 語法甘露:
var object = // 定義小寫的object基本類,用于實現(xiàn)最基礎(chǔ)的方法等 { isA: function (aType) // 一個判斷類與類之間以及對象與類之間關(guān)系的基礎(chǔ)方法 { var self = this ; while (self) { if (self == aType) return true ; self = self.Type; }; return false ; } }; function Class(aBaseClass, aClassDefine) // 創(chuàng)建類的函數(shù),用于聲明類及繼承關(guān)系 { function class_() // 創(chuàng)建類的臨時函數(shù)殼 { this .Type = aBaseClass; // 我們給每一個類約定一個Type屬性,引用其繼承的類 for ( var member in aClassDefine) this [member] = aClassDefine[member]; // 復制類的全部定義到當前創(chuàng)建的類 }; class_.prototype = aBaseClass; return new class_(); }; function New(aClass, aParams) // 創(chuàng)建對象的函數(shù),用于任意類的對象創(chuàng)建 { function new_() // 創(chuàng)建對象的臨時函數(shù)殼 { this .Type = aClass; // 我們也給每一個對象約定一個Type屬性,據(jù)此可以訪問到對象所屬的類 if (aClass.Create) aClass.Create.apply( this , aParams); // 我們約定所有類的構(gòu)造函數(shù)都叫Create,這和DELPHI比較相似 }; new_.prototype = aClass; return new new_(); }; // 語法甘露的應用效果: var Person = Class(object, // 派生至object基本類 { Create: function (name, age) { this .name = name; this .age = age; }, SayHello: function () { alert( " Hello, I'm " + this .name + " , " + this .age + " years old. " ); } }); var Employee = Class(Person, // 派生至Person類,是不是和一般對象語言很相似? { Create: function (name, age, salary) { Person.Create.call( this , name, age); // 調(diào)用基類的構(gòu)造函數(shù) this .salary = salary; }, ShowMeTheMoney: function () { alert( this .name + " $ " + this .salary); } }); var BillGates = New(Person, [ " Bill Gates " , 53 ]); var SteveJobs = New(Employee, [ " Steve Jobs " , 53 , 1234 ]); BillGates.SayHello(); SteveJobs.SayHello(); SteveJobs.ShowMeTheMoney(); var LittleBill = New(BillGates.Type, [ " Little Bill " , 6 ]); // 根據(jù)BillGate的類型創(chuàng)建LittleBill LittleBill.SayHello(); alert(BillGates.isA(Person)); // true alert(BillGates.isA(Employee)); // false alert(SteveJobs.isA(Person)); // true alert(Person.isA(Employee)); // false alert(Employee.isA(Person)); // true “語法甘露”不用太多,只要那么一點點,就能改觀整個代碼的易讀性和流暢性,從而讓代碼顯得更優(yōu)雅。有了這些語法甘露,JavaScript就很像一般對象語言了,寫起代碼了感覺也就爽多了!
原著:李戰(zhàn)(leadzen) http://www.cnblogs.com/leadzen/archive/2008/02/25/1073404.html |
|