建構函式:
new操作符用來產生一個新的對象.new後面必須要跟上一個函數,也就是我們常說的建構函式.建構函式的工作原理又是怎樣的呢?
先看一個例子:
- <SPAN style="FONT-SIZE: medium">
- function Person(name,sex) {
- this.name = name;
- this.sex = sex;
- }
- var per = new Person("sdcyst","male");
- alert("name:"+per.name+"_sex:"+per.sex); //name:sdcyst_sex:male</SPAN>
下面說明一下這個工作的步驟:
開始建立了一個函數(不是方法,只是一個普通的函數),注意用到了this關鍵字.以前我們提到過this關鍵字表示調用該方法的對象,也就是說通過對象調用"方法"的時候,this關鍵字會指向該對象(不使用對象直接調用該函數則this指向整個的script域,或者函數所在的域,在此我們不做詳細的討論).當我們使用new操作符時,javascript會先建立一個空的對象,然後這個對象被new後面的方法(函數)的this關鍵字引用!然後在方法中通過操作this,就給這個新建立的對象相應的賦予了屬性.最後返回這個經過處理的對象.這樣上面的例子就很清楚:先建立一個Null 物件,然後調用Person方法對其進行賦值,最後返回該對象,我們就得到了一個per對象.
prototype(原型)--在這裡會反覆提到"原型對象"和"原型屬性",注意區分這兩個概念.在javascript中,每個對象都有一個prototype屬性,這個屬性指向了一個prototype對象.
上面我們提到了用new來建立一個對象的過程,事實上在這個過程中,當建立了Null 物件後,new會接著操作剛產生的這個對象的prototype屬性.
每個方法都有一個prototype屬性(因為方法本身也是對象),new操作符產生的新對象的prototype屬性值和構造方法的prototype屬性值是一致的.構造方
法的prototype屬性指向了一個prototype對象,這個prototype對象初始只有一個屬性constructor,而這個constructor屬性又指向了prototype屬性所在的方
法.
這樣,當用建構函式建立一個新的對象時,它會擷取建構函式的prototype屬性所指向的prototype對象的所有屬性.對建構函式對應的prototype對象
所做的任何操作都會反應到它所產生的對象身上,所有的這些對象共用建構函式對應的prototype對象的屬性(包括方法).
看個具體的例子吧:
- <SPAN style="FONT-SIZE: medium">
- function Person(name,sex) { //建構函式
- this.name = name;
- this.sex = sex;
- }
- Person.prototype.age = 12; //為prototype屬性對應的prototype對象的屬性賦值
- Person.prototype.print = function() { //添加方法
- alert(this.name+"_"+this.sex+"_"+this.age);
- };
-
- var p1 = new Person("name1","male");
- var p2 = new Person("name2","male");
- p1.print(); //name1_male_12
- p2.print(); //name2_male_12
-
- Person.prototype.age = 18; //改變prototype對象的屬性值,注意是操作建構函式的prototype屬性
- p1.print(); //name1_male_18
- p2.print(); //name2_male_18</SPAN>
到目前為止,我們已經類比出了簡單的類的實現,我們有了建構函式,有了類屬性,有了類方法,可以建立"執行個體".
在下面的文章中,我們就用"類"這個名字來代替構造方法,但是,這僅僅是類比,並不是真正的物件導向的"類".
在下一步的介紹之前,我們先來看看改變對象的prototype屬性和設定prototype屬性的注意事項:
給出一種不是很恰當的解釋,或許有助於我們理解:當我們new了一個對象之後,這個對象就會獲得建構函式的prototype屬
性(包括函數和變數),可以認為是建構函式(類)繼承了它的prototype屬性對應的prototype對象的函數和變數,也就是說,
prototype對象類比了一個超類的效果.聽著比較拗口,我們直接看個執行個體吧:
- <SPAN style="FONT-SIZE: medium">function Person(name,sex) { //Person類的建構函式
- this.name = name;
- this.sex = sex;
- }
- Person.prototype.age = 12; //為Person類的prototype屬性對應的prototype對象的屬性賦值,
- //相當於為Person類的父類添加屬性
- Person.prototype.print = function() { //為Person類的父類添加方法
- alert(this.name+"_"+this.sex+"_"+this.age);
- };
-
- var p1 = new Person("name1","male"); //p1的age屬性繼承子Person類的父類(即prototype對象)
- var p2 = new Person("name2","male");
-
- p1.print(); //name1_male_12
- p2.print(); //name2_male_12
-
- p1.age = 34; //改變p1執行個體的age屬性
- p1.print(); //name1_male_34
- p2.print(); //name2_male_12
-
- Person.prototype.age = 22; //改變Person類的超類的age屬性
- p1.print(); //name1_male_34(p1的age屬性並沒有隨著prototype屬性的改變而改變)
- p2.print(); //name2_male_22(p2的age屬性發生了改變)
-
- p1.print = function() { //改變p1對象的print方法
- alert("i am p1");
- }
-
- p1.print(); //i am p1(p1的方法發生了改變)
- p2.print(); //name2_male_22(p2的方法並沒有改變)
-
- Person.prototype.print = function() { //改變Person超類的print方法
- alert("new print method!");
- }
-
- p1.print(); //i am p1(p1的print方法仍舊是自己的方法)
- p2.print(); //new print method!(p2的print方法隨著超類方法的改變而改變)</SPAN>