這個時候,首先調用Alien構造函數運行,創建一個空對象alien,把構造函數中的this綁定到alien上,然後運行Actor.call(alien,scene,0,0)產生了alien.id=++Actor.nextID,然後添加其它私有屬性,但當又遇到id這個屬性的時候,alien.id=++... ...
假設想給上節講的場景圖庫添加收集診斷信息的功能。這對於調試和性能分析很有用。
38條示例續
給每個Actor實例一個唯一的標識數。
添加標識數
function Actor(scene,x,y){
this.scene=scene;
this.x=x;
this.y=y;
this.id=++Actor.nextID;
scene.register(this);
}
Actor.nextID=0;
現在我們需要對Actor的子類做同樣的事。假設,Alien類代表太空飛船的敵人。除了其角色標識數外,我們希望每個外星人都有一個單獨標識數。
function Alien(scene,x,y,direction,speed,strength){
Actor.call(this,scene,x,y);
this.direction=direction;
this.speed=speed;
this.strength=0;
this.damage=0;
this.id=++ Alien.nextID;
}
Alien.nextID=0;
這裡導致Alien類與其父類Actor之間衝突。兩個類都試圖給實例屬性id寫數據。雖然每個類都認為該屬性是“私有”的(即只有直接定義在該類中的方法才能獲取該屬性),然而事實是該屬性存儲在實例對象上並命名為一個字元串。如果在繼承體系中的兩個類指向相同的屬性名,那麼它們指向的是同一個屬性。
執行
當我們調用下麵這個代碼來看一下,上面的執行過程。
var alien=new Alien(scene,0,0,'lt',100,10);
這個時候,首先調用Alien構造函數運行,創建一個空對象alien,把構造函數中的this綁定到alien上,然後運行Actor.call(alien,scene,0,0)產生了alien.id=++Actor.nextID,然後添加其它私有屬性,但當又遇到id這個屬性的時候,alien.id=++Alien.nextID,把上面從基類構造函數產生的id進行了修改。這個時候,id的屬性就產生了歧義。
修正
因此,子類必須始終留意其父類使用的所有屬性,即使那些屬性在概念上是私有的。該例子顯而易見的解決方法是對Actor標識數和Alien標識數使用不同的屬性名。
function Actor(scene,x,y){
this.scene=scene;
this.x=x;
this.y=y;
this.id=++Actor.nextID;
scene.register(this);
}
Actor.nextID=0;
function Alien(scene,x,y,direction,speed,strength){
Actor.call(this,scene,x,y);
this.direction=direction;
this.speed=speed;
this.strength=0;
this.damage=0;
this.alienID=++ Alien.nextID;
}
Alien.nextID=0;
提示
-
留意父類使用的所有屬性名
-
不要在子類中重用父類的屬性名
附錄:完整結構關係圖
下麵是一張38條和39條里添加標識符後,所有類之間的關係圖。