ExtJS 4.2 03 Javascript 中的類

參考文章:

http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html

http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html


ExtJS 比較難入門的原因,主要是因爲其中用到了Javascript 中面向對象方面的東西,Extjs中有大量的類,而在實際使用時,也需要繼承Extjs標準類。我們先了解下Javascript中類相關的知識。Javascript是一種基於對象(object-based)的語言,你遇到的所有東西幾乎都是對象。但是,它又不是一種真正的面向對象編程(OOP)語言,因爲它的語法中沒有class(類)。這就導致Javascript的Object模型很獨特,和其他語言都不一樣。

生成對象的原始模式

定義類最簡單的方式就是用大括號,我們把貓看成一個對象,它有"名字"和"顏色"兩個屬性。

?
1
2
3
4
5
var cat1 = {
            name : '大毛',
            color : '黃色'
};
console.dir(cat1)

這就是最簡單的封裝了,把兩個屬性封裝在一個對象裏面。

構造函數模式

爲了解決從原型對象生成實例的問題,Javascript提供了一個構造函數(Constructor)模式。所謂"構造函數",其實就是一個普通函數,但是內部使用了this變量。對構造函數使用new運算符,就能生成實例,並且this變量會綁定在實例對象上。

?
1
2
3
4
5
6
function Cat(name,color){
    this.name = name;
    this.color = color;
}
var cat1 = new Cat('大毛','黃色');
console.dir(cat1);


Javascript 規定,每個對象都有一個constructor屬性,指向構造函數。

?
1
alert(cat1.constructor == Cat); // true


Javascript還提供了一個 instanceof 運算符,驗證類與實例對象之間的關係。

?
1
alert(cat1 instanceof Cat); // true


構造函數方法很好用,但是存在浪費內存的問題。對象實例之間不能共享數據。Javascript規定,每一個構造函數都有一個prototype屬性,指向另一個對象。這個對象的所有屬性和方法,都會被構造函數的實例繼承。可以把那些不變的屬性和方法,直接定義在prototype對象上。

?
1
2
3
4
5
6
7
8
9
10
11
function Cat(name,color){
    this.name = name;
    this.color = color;
}
Cat.prototype.type = '貓科動物';
Cat.prototype.eat = function () {
    alert('喫.....')
};
var cat1 = new Cat('大毛','黃色');
var cat2 = new Cat('二毛','黃色');
alert(cat1.eat == cat2.eat);

所有實例的type屬性和eat()方法,其實都是同一個內存地址,指向prototype對象,因此就提高了運行效率.

每個實例對象都有一個hasOwnProperty()方法,用來判斷某一個屬性到底是本地屬性,還是繼承自prototype對象的屬性

?
1
2
console.info(cat1.hasOwnProperty("name"));
console.info(cat1.hasOwnProperty("type"));

in運算符可以用來判斷,某個實例是否含有某個屬性,不管是不是本地屬性。in運算符還可以用來遍歷某個對象的所有屬性。

?
1
2
3
4
console.info("name" in cat1);
for(var prop in cat1){
    console.info('cat1['+prop+']='+cat1[prop]);
}

構造函數的繼承

Javascript 中的繼承全靠一種奇特的原型鏈(prototype chain)來實現。前面已經介紹了,Javascript 規定每個構造函數都有一個prototype 屬性,這個prototype屬性指向的對象的所有屬性和方法,都可以被這個構造函數所有。

?
1
2
3
4
5
6
7
function Animal(){
    this.species = "動物";
}
function Cat(name,color){
    this.name = name;
    this.color = color;
}

想讓Cat 是Animal的子類,可以通過Cat 的 prototype 屬性實現繼承。

?
1
2
3
4
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
var cat1 = new Cat("大毛","黃色");
alert(cat1.species); // 動物

第一行,把 Cat 的原型屬性 prototype 指向 Animal,這 Cat 就可以訪問到 Animal 中的屬性和方法。

第二行,其實是手工糾正。原因是:每個對象都有一個constructor屬性,指向它的構造函數。其實每個prototype 也有一個constructor屬性。同時實例的constructor屬性,默認調用prototype對象的constructor屬性。如果重新指定了prototype屬性,那麼實例的constructor屬性 和 prototype對象的constructor屬性就不一致了。所以就需要手工糾正。

這是很重要的一點,編程時務必要遵守。即如果替換了prototype對象,下一步必然是爲新的prototype對象加上constructor屬性,並將這個屬性指回原來的構造函數。

?
1
2
o.prototype = {};
o.prototype.constructor = o;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章