2025-02-15

 

原型Prototype是一個設計模式,但是也可用來設計繼承,它有自己的簡單性,可以模擬出面向對象功能,但是在設計

復雜的繼承層次的時候比較蹩腳。

在JS中要實現復雜的面向對象模型,需要自己做大量的工作,先研究和檢驗JS的原型鏈和構造函數,原則上不需要構造函數和類也是可以OO的

 

1,定義一個類

/**

 * 定義一個構造函數Plane,這個時候Plane的prototype指向瞭一個Object構造出來的對象,同時有一個constructor屬性指回Plane

 * 這個構造函數在和new一起被執行的時候,會傳入一個由Object構造的幹凈對象作為this,當然還有其他參數,在真正執行代碼之前

 * 就已經介紹構造函數的prototype給新對象讓他們關聯起來,然後執行構造函數中的代碼,一般做數據初始化而不放置方法

 * @param x

 * @param y

 */

 

var Plane = function(x, y) {

    //檢驗是否設置原型true

    alert(this.__proto__ == Plane.prototype);

    this.x = x;

    this.y = y;

};

 

//靜態字段

Plane.STATIC_FIELD = 2;

 

//靜態方法

Plane.staticFunction = function() {

    alert(Plane.STATIC_FIELD);

}

 

//檢驗構造函數上的prototype的constructor是否等於構造函數  true

alert(Plane.prototype.constructor == Plane);

 

/**

 * 在原型上設定一個方法,這樣每個實例都共享這些方法

 */

Plane.prototype.XY = function() {

    alert(this.x * this.y);

};

 

//實例化對象

var planeObject = new Plane(2, 3);

 

//Object的protype上的原型鏈為空true

alert(Object.prototype.__proto__ == null);

 

//檢驗構造函數的prototype上的對象的原型是否是Object的prototype上的對象  true

alert(Plane.prototype.__proto__ == Object.prototype);

 

//檢驗實例對象的原型是否是構造函數的prototype   true

alert(planeObject.__proto__ == Plane.prototype);

 

planeObject.XY();

Plane.staticFunction();

2,繼承這個類

/**

 * 如果要實現繼承結構,超類的不變量需要維護,在JS中,如果隻是從Object繼承,不需要維護,因為Object中根本沒有屬性,當然除瞭那個constructor

 * Java的Object也是隻有方法,沒有屬性的

 * 現在如果我們要繼承Plane,首先構造對象的時候需要調用超類的構造函數構造超類那一部分

 * 上面我們可以認為Plane是Object的子類,特點就是Plane的prototype是Object構造的,那麼要讓一個類成為Plane的子類,新類的prototype也需要是Plane構造的

 * 問題來瞭,從Plane構造出來那個對象_proto_肯定指向Plane.prototype,但是可能會在對象上設置Plane初始的一些數據,而我們隻希望繼承行為,所以存在兩種方法:

 * 1,手動delete掉

 * 2,用一個幹凈函數做嫁接,我們的最終目的是:要一個新對象,它的_proto_指向Plane的prototype,它的constructor指向新構造函數,我們當然希望

 直接將Plane的原型設置在_proto_上,但是js是不允許的,所以要通過函數構造的方式,第一種會留有垃圾數據,采用第二重把Plane的prototype取出來放到一個幹凈的函數上,用那個函數

 構造一個對象,然後再對構造出來的對象設置constructor就完美瞭,這也是Ext的做法

 */

 

var Space = function(x, y, z) {

    //用this調用超類構造函數

    Plane.call(this, x, y);

    //this.super(x, y);

 

    this.z = z;

};

 

 

/**

 * 要讓Space繼承Plane,需要讓Space的原型是Plane的實例,現在我們是在手動設置原型,這原本JS引擎做的事

 *

 */

Space.prototype = new Plane();

 

//在子類的原型上放一個不變的屬性指向超類,這種方法,如果多於兩次繼承,當this.super走到超類構造函數,因為this.super始終指向這個超類,所以會無限遞歸

Space.prototype.super = Plane;

 

/**

 * 我們隻希望繼承方法和不變量,所以要刪除超類自身的數據字段,雖然那些字段的值是undefined

 */

 

alert(Space.prototype.x); //undefined

 

delete Space.prototype.x;

 

delete Space.prototype.y;

 

 

/**

 * 原型除瞭是個對象,還有個constructor指向它所在的函數,所以要設置這個值

 */

Space.prototype.constructor = Space;

 

/**

 * 子類覆蓋父類進行裝飾

 */

Space.prototype.XY = function() {

    alert("Before Invoke Super Method");

    Plane.prototype.XY.call(this);

 

}

 

Space.prototype.XYZ = function() {

    alert(this.x * this.y * this.z);

}

 

var spaceObject = new Space(2, 3, 4);

 

//調用覆蓋的方法

spaceObject.XY();

 

//調用自身的方法

spaceObject.XYZ();

3,使用幹凈函數做嫁接實現原型繼承

//一個幹凈函數做嫁接,第二種方法

var F = function() {

}

//嫁接過去

F.prototype = Plane.prototype;

Space.prototype = new F();

 

摘自 Adley

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *