JS基礎——建構函式VS原型函數
JS是一種基於對象的語言,在使用過程中不免遇到複製對象的問題,但通常我們採用的直接賦值‘obj1=obj2’這種做法會出現資料覆蓋問題。也就是對象引用過程中引用地址一致,導致對象資料被修改的問題。這時我們可以採用原廠模式來對對象進行執行個體化,從而實現對象的引用地址一致導致的資料覆蓋問題。但此時,問題隨之又來了,使用原廠模式,對於具體的執行個體所屬的具體對象又搞不清楚,在JS中採用構造方法來解決對象執行個體的資料覆蓋問題(這裡和其它語言的原理是類似的)。
一、建構函式
在其它語言中接觸過建構函式,通常它與類的名稱一致。但在JS中並沒有明確的‘類’這個概念。在我看來,它聲明的對象從某種程度上說就是一種類,因為它的每個對象都可以有自己對應的執行個體。
建構函式解決資料覆蓋:
function Box(name,age){this.name=name;this.age=age;this.run=function(){return this.name+this.age+'運行中...';} }function Desk(name,age){this.name=name;this.age=age;this.run=function(){return this.name+this.age+'運行中...';} }
對它進行調用:
var box1=new Box('lee',22); var box2=new Desk('john',66);
alert(box1 instanceof Box);//TRUEalert(box2 instanceof Box); //可以識別具體哪個對象的執行個體,FALSE
同時,建構函式可以進行對象冒充,來改變對象自身的範圍,實現自身所不能實現的行為。但同時,又引出了另外一個問題,建構函式體內對於參考型別資料引用地址出現不一致現象,這說明在記憶體中對於完全相等的兩個或多個資料,要用對應大小的記憶體來盛放,這樣無疑造成了記憶體浪費現象。當然,我們可以採用在建構函式體外將參考型別進行單獨聲明,但是這種方法封裝性很差,很容易被外界惡意調用。所以,這裡JS中用到了原型。
二、原型函數
JS中建立的每一個函數都有一個prototype原型屬性,這個屬性也是一個對象。它的用途是包含可以由特定類型的所有執行個體共用的屬性和方法。如所示,函數的原型對象為該函數的所有執行個體所共用。
中__proto__是原型對象的指標,它指向原型對象,同時constructor為原型對象的構造屬性,執行具體的所屬的建構函式對象。在實際應用中可以通過constructor屬性來改變一個原型對象所屬的建構函式對象。
為函數建立原型屬性和方法:
function Box(){} //建構函式體內什麼都沒有,如果有,就叫做執行個體屬性和執行個體方法Box.prototype.name='lee';//原型屬性Box.prototype.age=22;Box.prototype.run=function(){ //原型方法return this.name+this.age+'運行中...';}用這種方法,可以解決上面遺留的引用地址不一致的問題(建構函式+原型)。
可以通過Box.prototype.isPrototypeOf(box1)來對執行個體所屬的原型對象進行判斷。同時在建立函數的原型時,也可以通過字面量的方法來建立:
Box.prototype={name:'lee',age:100,run:function(){return this.name+this.age+'運行中...';}}
以上是有關JS中建構函式和原型函數的一些基礎知識,小結一下:
1.建構函式在執行個體化時,必須使用new來操作,聲明時不需要new object,隱含自身已經new了
2、建構函式可以用來解決對象執行個體化中資料覆蓋問題,但會造成引用地址不一致問題
3、原型函數解決了引用地址不一致問題
4、但原型函數可以實現共用但不能進行重寫,會將原來的資訊覆蓋。
對於重寫問題,可以採用原型+建構函式結合來各司其職。後面再做詳細總結。