構(gòu)造對象
好了,接下我們來討論一下對象的另一種創(chuàng)建方法。
除JSON外,在JavaScript中我們可以使用new操作符結(jié)合一個函數(shù)的形式來創(chuàng)建對象。例如:
function MyFunc() {}; //定義一個空函數(shù) var anObj = new MyFunc(); //使用new操作符,借助MyFun函數(shù),就創(chuàng)建了一個對象 JavaScript的這種創(chuàng)建對象的方式可真有意思,如何去理解這種寫法呢? 其實,可以把上面的代碼改寫成這種等價形式: function MyFunc(){}; var anObj = {}; //創(chuàng)建一個對象 MyFunc.call(anObj); //將anObj對象作為this指針調(diào)用MyFunc函數(shù)
我們就可以這樣理解,JavaScript先用new操作符創(chuàng)建了一個對象,緊接著就將這個對象作為this參數(shù)調(diào)用了后面的函數(shù)。其實,JavaScript內(nèi)部就是這么做的,而且任何函數(shù)都可以被這樣調(diào)用!但從 “anObj = new MyFunc()” 這種形式,我們又看到一個熟悉的身影,C++和C#不就是這樣創(chuàng)建對象的嗎?原來,條條大路通靈山,殊途同歸啊!
君看到此處也許會想,我們?yōu)槭裁床豢梢园堰@個MyFunc當作構(gòu)造函數(shù)呢?恭喜你,答對了!JavaScript也是這么想的!請看下面的代碼:
1 function Person(name) //帶參數(shù)的構(gòu)造函數(shù) 2 { 3 this.name = name; //將參數(shù)值賦給給this對象的屬性 4 this.SayHello = function() {alert("Hello, I'm " + this.name);}; //給this對象定義一個SayHello方法。 5 }; 6 7 function Employee(name, salary) //子構(gòu)造函數(shù) 8 { 9 Person.call(this, name); //將this傳給父構(gòu)造函數(shù) 10 this.salary = salary; //設置一個this的salary屬性 11 this.ShowMeTheMoney = function() {alert(this.name + " $" + this.salary);}; //添加ShowMeTheMoney方法。 12 }; 13 14 var BillGates = new Person("Bill Gates"); //用Person構(gòu)造函數(shù)創(chuàng)建BillGates對象 15 var SteveJobs = new Employee("Steve Jobs", 1234); //用Empolyee構(gòu)造函數(shù)創(chuàng)建SteveJobs對象 16 17 BillGates.SayHello(); //顯示:I'm Bill Gates 18 SteveJobs.SayHello(); //顯示:I'm Steve Jobs 19 SteveJobs.ShowMeTheMoney(); //顯示:Steve Jobs $1234 20 21 alert(BillGates.constructor == Person); //顯示:true 22 alert(SteveJobs.constructor == Employee); //顯示:true 23 24 alert(BillGates.SayHello == SteveJobs.SayHello); //顯示:false
這段代碼表明,函數(shù)不但可以當作構(gòu)造函數(shù),而且還可以帶參數(shù),還可以為對象添加成員和方法。其中的第9行,Employee構(gòu)造函數(shù)又將自己接收的this作為參數(shù)調(diào)用Person構(gòu)造函數(shù),這就是相當于調(diào)用基類的構(gòu)造函數(shù)。第21、22行還表明這樣一個意思:BillGates是由Person構(gòu)造的,而SteveJobs是由Employee構(gòu)造的。對象內(nèi)置的constructor屬性還指明了構(gòu)造對象所用的具體函數(shù)!
其實,如果你愿意把函數(shù)當作“類”的話,她就是“類”,因為她本來就有“類”的那些特征。難道不是嗎?她生出的兒子各個都有相同的特征,而且構(gòu)造函數(shù)也與類同名嘛!
但要注意的是,用構(gòu)造函數(shù)操作this對象創(chuàng)建出來的每一個對象,不但具有各自的成員數(shù)據(jù),而且還具有各自的方法數(shù)據(jù)。換句話說,方法的代碼體(體現(xiàn)函數(shù)邏輯的數(shù)據(jù))在每一個對象中都存在一個副本。盡管每一個代碼副本的邏輯是相同的,但對象們確實是各自保存了一份代碼體。上例中的最后一句說明了這一實事,這也解釋了JavaScript中的函數(shù)就是對象的概念。
同一類的對象各自有一份方法代碼顯然是一種浪費。在傳統(tǒng)的對象語言中,方法函數(shù)并不象JavaScript那樣是個對象概念。即使也有象函數(shù)指針、方法指針或委托那樣的變化形式,但其實質(zhì)也是對同一份代碼的引用。一般的對象語言很難遇到這種情況。
不過,JavaScript語言有大的靈活性。我們可以先定義一份唯一的方法函數(shù)體,并在構(gòu)造this對象時使用這唯一的函數(shù)對象作為其方法,就能共享方法邏輯。例如:
function SayHello() //先定義一份SayHello函數(shù)代碼 { alert("Hello, I'm " + this.name); }; function Person(name) //帶參數(shù)的構(gòu)造函數(shù) { this.name = name; //將參數(shù)值賦給給this對象的屬性 this.SayHello = SayHello; //給this對象SayHello方法賦值為前面那份SayHello代碼。 };
var BillGates = new Person("Bill Gates"); //創(chuàng)建BillGates對象 var SteveJobs = new Person("Steve Jobs"); //創(chuàng)建SteveJobs對象 alert(BillGates.SayHello == SteveJobs.SayHello); //顯示:true
其中,最后一行的輸出結(jié)果表明兩個對象確實共享了一個函數(shù)對象。雖然,這段程序達到了共享了一份方法代碼的目的,但卻不怎么優(yōu)雅。因為,定義SayHello方法時反映不出其與Person類的關(guān)系!皟(yōu)雅”這個詞用來形容代碼,也不知道是誰先提出來的。不過,這個詞反映了程序員已經(jīng)從追求代碼的正確、高效、可靠和易讀等基礎上,向著追求代碼的美觀感覺和藝術(shù)境界的層次發(fā)展,程序人生又多了些浪漫色彩。
顯然,JavaScript早想到了這一問題,她的設計者們?yōu)榇颂峁┝艘粋有趣的prototype概念。
出處:軟件真諦
責任編輯:moby
上一頁 對象素描 下一頁 初看原型
◎進入論壇網(wǎng)頁制作、WEB標準化版塊參加討論,我還想發(fā)表評論。
|