標籤:
1、建構函式模式
建構函式用來建立特定的類型的對象。如下所示:
function Person(name,age,job){ this.name=name; this.job=job; this.age=age; this.sayName=function(){ alert(this.name); };}var person1=new Person(‘nick‘,20,‘student‘);
var person2=new Person(‘nick‘,20,‘student‘);
alert(person1.sayName==person2.sayName);//false
建構函式特點:不需要顯示地建立對象,直接將屬性和方法賦給this對象;
建立構造建構函式的執行個體,需要用new操作符,new操作符會建立一個新對象,而後將建構函式的範圍指向新的對象。
建構函式的缺點:上面的例子中,建構函式內的sayName()方法,也可以寫為 this.sayName()=new Function("alert(this.name)") 可以看出來,每次建立一個Person的執行個體都會建立一個新的sayName執行個體,不同的執行個體,有不同的範圍鏈和標識符解析,因此不同執行個體上的同名函數不相等!
對於這個缺點,我們可以考慮一下:既然在函數內建立的新的sayName執行個體有不同的範圍鏈,假設我們將sanName函數定義轉義到建構函式外部,那麼sayName函數就處於一個全域環境中了!
function Person(name,age,job){ ...}function sayName(){ alert(this.name);}var person2=new Person1(‘alex‘,20,‘student‘); var person3=new Person1(‘alexx‘,20,‘student‘); alert(person2.sayName==person3.sayName);//true 兩個都是引用同一個全域範圍中定義的函數
2、原型模式
JS進階程式設計的P147對於原型屬性的解釋是這樣的:每個函數都有一個prototype原型屬性,它是一個指標,指向一個對象,這個對象的用途是包含可以由特定類型的所有執行個體共用的屬性和方法。怎麼理解這句話呢,其實就是我可以建立2個執行個體person,這兩個對象執行個體繼承了建構函式的屬性,其中包括prototype,因此它們也就具有了prototype中的所有執行個體共用的屬性和方法了!
如下,原型模式中,直接把屬性方法寫到prototype中
function Person(){}Person.prototype.name=‘nick‘;Person.prototype.age=20;Person.prototype.sayName=function(){ alert(this.name); };var person1=new Person();var person2=new Person();person2.name="jack";alert(person1.name);//nick 繼承Person的原型屬性,先讀取person1執行個體中的屬性,沒找到name屬性再搜尋原型對象中的屬性alert(person2.name);//jack 在執行個體中添加一個屬性,將同名的原型屬性屏蔽了alert(person1.hasOwnproperty(‘name));//true person1執行個體有name屬性alert(person2.hasOwnproperty(‘name));//true person2執行個體沒有name屬性,它的name屬性存在於所繼承的Person原型屬性中
(1)通過hasOwnProperty()方法可以檢測一個屬性是存在執行個體還是原型中。
(2)通過in操作符,只要執行個體或者原型有所尋找屬性就返回true;
alert("name" in person2);//true name在person的原型中
原型模式的缺陷:
編寫原型對象,可以使用對象字面量,但是會導致Person.constructor屬性不再指向Person,即
alert(person constructor==Person);//false
這方面在JS進階程式設計P154中有詳細講到。
還有一個缺陷:前面說到,原型屬性是被執行個體共用的,對於包含基本值的屬性來說,如果在某個執行個體中把某個原型屬性修改了就會反映在其他執行個體中。
function Person(){}//用對象字母兩來重寫整個原型對象更簡便Person.prototype={ name:‘NICK‘, age:20, job:‘student‘, friend:[‘aa‘,‘bb‘]; sayName:function(){ alert(this.name); }}var person1=new Person();var person2=new Person();person1.friend.push(‘cc‘);alert(person2.friend);//[‘aa‘,‘bb‘,‘cc‘];在person1中修改的內容反映在person2中
組合使用建構函式模式和原型模式
這種方式的好處在於:建構函式可以保持執行個體屬性的獨立,原型模式可以定義共用的屬性的方法;
1 function Person(name,age,job){ 2 this.name=name; 3 this.age=age; 4 this.job=job; 5 this.friend=[‘aa‘,‘bb‘]; 6 } 7 8 Person.prototype={ 9 constructor:Person,10 sayName:function(){11 alert(this.name);12 }13 }14 var person1=new Person(‘nick‘,20,‘student‘);15 var person2=new Person(‘jerry‘,10,‘student‘);16 17 person1.friend.push(‘cc‘);18 19 alert(person1.name);20 alert(person1.friend);21 alert(person2.name);22 alert(person2.friend);//aa bb 往person1的friend添加cc,不會影響到person2因為friend不是原型屬性
理解了原型模式,對於後面原型鏈的認識理解很重要,比如原型鏈的問題,原型鏈是通過
function SuperType(){ this.color=[‘aa‘,‘bb‘]; }function Subtype(){}Subtype.prototype=new SuperType();//繼承supertype Subtype.prototype成為SuperType的一個執行個體,因此Subtype建立的執行個體,都會擁有SubType的原型屬性,這個原型屬性是共用的!var instance1=new Subtype();var instance2=new Subtype();instance1.color.push(‘cc‘);alert(instance2.color);//[‘aa‘,‘bb‘,‘cc‘];
這個缺點同樣可以使用建構函式來解決。找時間再寫JS物件導向(2)——原型鏈
第一次寫自己學習的一些總結呢,最近在在JS進階程式設計,感覺看了對JS的理解提升很大!加油!
JS物件導向(1)——建構函式模式和原型模式