與其他進階語言不同,javascript的類和對象比較特殊,這裡將詳細闡述。
1.javascript沒有真正的類。
2.因為不是強型別語言,所以javascript不支援早期繫結。
3.js中,所有的對象並非同等建立的,一般分為三類:
(1)本機物件:定義為“獨立於宿主環境的js實現提供的對象”。包括Object, Function,Array,String,Boolean,Number,Date,RegExp,Error,EvalError,RangeError,ReferrenceError,SyntaxError,TypeError,URIError.
(詳細介紹見另一篇文章(javascript常用本機物件的使用))
(2) 內建對象:定義為“獨立於宿主環境的js實現提供的對象,在程式開始執行時出現”。從定義可以看出,每個內建對象都是本機物件。內建對象有兩個:Global,Math.
(3) 宿主對象:定義為:“有js實現的宿主環境所提供的對象”。所有的DOM和BOM對象都是宿主對象。
4.範圍。
對js講對象的範圍幾乎毫無意義,因為js只存在一種範圍,公用範圍。因此,定義自己的類或對象時,必須格外小心,因為預設它們都是公用的。
5.this關鍵字
this總是指向調用該方法的對象。
var oCar = new Object;
oCar.color = "red";
oCar.showColor = function (){
alert(this.color); //outputs "red",this指向oCar
}
6.定義類:
(1).工廠方式
function createCar(sColor,iDoors,iMpg){
var oCar = new Object;
oCar.color = sColor;
oCar.doors = iDoors;
oCar.mpg = iMpg;
oCar.showcolor = function(){
alert(this.color);
}
return oCar;
}
var oCar1 = CreateCar("red",4,23);
var oCar2 = CreateCar("blue",2,20);
oCar1.showColor();//ouputs "red"
oCar2.showColor();//outputs "blue"
這種工廠方式的缺點是:每次調用craeteCar,都要建立新函數showcolor(),每一個對象都有自己的showcolor版本
(2).建構函式方式
function createCar(sColor,iDoors,iMpg){
var oCar = new Object;
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.showcolor = function(){
alert(this.color);
}
}
var oCar1 = new createCar("red",4,23);
var oCar2 = new createCar("blue",2,20);
同Factory 方法一樣,建構函式方式同樣會重複產生函數,為每個對象建立獨立的函數版本
(3).原型方式
function Car(){
Car.prototype.color = "red";
Car.prototype.doors = 4;
Car.prototype.mpg = 23;
Car.prototype.showcolor = function(){
alert(this.color)
}
}
var oCar1 = new Car();
var oCar2 = new Car();
該方法利用了對象的prototype屬性,用空的建構函式來設定類名,然後所有的屬性和方法都被直接賦予prototype屬性。
問題:1.建構函式沒有參數,使用原型方式時,不能通過給建構函式傳遞參數初始化屬性;2.也是最致命的問題,當屬性指向的是對象
,而不是函數時,對象是被多個執行個體共用的(函數共用不會造成任何問題):
function Car(){
Car.prototype.color = "red";
Car.prototype.doors = 4;
Car.prototype.mpg = 23;
Car.prototype.dirvers = new Array("Mike","Sue");
Car.prototype.showcolor = function(){
alert(this.showcolor);
}
}
var oCar1 = new Car();
var oCar2 = new Car();
oCar1.dirvers.push("Matt");
alert(oCar1.dirvers)://outputs "Mike,Sue,Matt"
alert(oCar2.dirvers)://outputs "Mike,Sue,Matt"
改變oCar1.dirvers,同時也改變了oCar2.dirvers !!!
(4).混合的建構函式/原型方式
這種方式汲取了建構函式和原型方式的優點:
function Car(sColor,iDoors,iMpg){
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.dirvers = new Array("Mike","Sue");
}
Car.prototype.showcolor = function(){
alert(this.color);
}
var oCar1 = new Car("red",4,23);
var oCar2 = new Car("blue",2,23);
oCar1.drivers.push("Matt");
alert(oCar1.drivers);//outpust "Mike,Sue,Matt"
alert(oCar2.drivers);//outputs "Mike,Sue"
這種方式,所有的非函數屬性都在建構函式裡建立,而在原型裡建立函數showcolor,避免了記憶體的浪費。除了視覺上的不習慣,這種解決方式堪稱完美。
(5).動態原型方法
上面提到,混合的建構函式/原型方式,給人的視覺上不習慣。封裝這一概念體現的很不明確。於是產生了動態原型方法,它與上面方法的
唯一區別是賦予對象方法的位置:
function Car(sColor,iDoors,iMpg){
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.drivers = new Array("Mike","Sue");
if(typeof Car._initialized =="undefined"){
Car.prototype.showcolor = function(){
alert(this.color);
}
}
car._initialized = true;
}
這樣封裝,傳統的OOP開發人員會高興地發現,這樣看起來舒服多了。
(6).混合工廠方式
function Car(){
var oCar = new Object;
oCar.color ="red";
oCar.doors = 4;
oCar.mpg =23;
oCar.showcolor = function (){
alert(this.color);
}
return oCar;
}
var car = new Car();
與工廠方式不同,僅僅是產生對象的方式,使用了new。其實因為建構函式內部調用了new,這個new將被忽略。
這種方式與經典工廠方式存在相同的問題。極不提倡使用這種方式。