实例化后更新相同类型的所有对象的属性

时间:2014-06-03 13:38:15

标签: javascript inheritance prototypal-inheritance

我目前面临一个棘手的问题,我无法在javascript中解决。例如,我有一个函数对象Unit。这是基础对象。

有两个函数对象TankAirDefense是原型继承自Unit

A"孩子" Unit有两个属性level(正常整数)和damagePerSecond(一个整数数组,其中索引表示该级别上的每秒伤害的级别和值)。

level应该是"静态"属性,所以每当我更改 AirDefense Tank 的实例级别时,之前创建的每个实例都必须是更新并应用更改的级别

但是也应该有一个静态更改级别的界面,这样我就不必在具体实例上调用setLevel方法,而是在函数对象本身上调用。

问题在于我正在实现一个名为getDamagePerSecond()的方法,它返回当前级别的每秒伤害。但是父母不知道具体子对象的当前级别。

我不能在基础对象上使用静态属性,因为它会为对象TankAirDefense设置级别,但是应该为每个子对象分隔级别。

tl; dr:我想从父对象中使用子对象静态属性,但我还不知道父对象中的子对象。

我将提供迄今为止我尝试过的内容,以便了解这些对象如何协同工作。

单元

function Unit(){
    this.level;
    this.damagePerSecond;   
}
Unit.prototype.getDamagePerSecond = function(){
    return this.damagePerSecond[this.level];
};

Unit.prototype.getLevel = function(){
    return this.level+1;
}

function Tank(){

    this.level = Tank.level || 0;
    this.dps = [5,10,15];

}

Tank.prototype = new Unit();
Tank.setLevel = function(level){
    Tank.level = level-1;   
}

的AirDefense

function AirDefense(){

    this.level = AirDefense.level || 0;
    this.dps = [1,5,9];

}

AirDefense.prototype = new Unit();
AirDefense.setLevel = function(level){
    AirDefense.level = level-1; 
}

主要(正确结果

Tank.setLevel(5);

var t = new Tank();
var a = new AirDefense();

console.log(t.getLevel()); //outputs 5
console.log(a.getLevel()); //outputs 1

主要(错误的结果

var t = new Tank();
Tank.setLevel(5);
var a = new AirDefense();

console.log(t.getLevel()); //outputs 1 - should be 5
console.log(a.getLevel()); //outputs 1

我基本上做的是伪造具体对象中的静态属性。 Level是我的子对象的静态属性。在实例化期间,我有一个额外的实例属性,其级别将设置为假静态属性的值。

但是这里出现了一些问题:

  1. 我只能在实例化之前为对象类型设置一个级别。但我想改变两者的水平,所有已经实例化的对象以及未来的对象。

  2. 使用这种方法,我需要在所有子对象上实现setLevel()方法。我认为这与干相反。

  3. 通过提供静态接口,无法直接发送已存在的具体实例

  4. 如果我在谈论原型时使用了不常见的术语,我很抱歉。我来自具有经典OO方法的语言。

    我还不熟悉原型继承,所以我希望有人能给我一个正确的方向。

1 个答案:

答案 0 :(得分:1)

所有Tank实例应该共享级别吗?你可以这样做:

function Unit(){}
Unit.prototype.getLevel = function(){
    return this.level+1;
};
function Tank(){
    //level should be shared by all Tanks
    //  setting this.level shadows Tank.prototype.level
    //  so let's not do that
//    this.level = Tank.level || 0;
}
//not sure why you want a Unit instance to be
//  prototype of all Tanks
Tank.prototype = Object.create(Unit.prototype);
Tank.prototype.constructor=Tank;
Tank.prototype.level=5;
Tank.prototype.setLevel = function(level){
  //set Tank.prototype.level so it's shared
  //  for all tank instances
  Tank.prototype.level = level-1;   
}
//same for AirDefense
var t1 = new Tank();
var t2 = new Tank();
console.log("t1 level:",t1.level,"t2 level",t2.level);
console.log("t1 getLevel:",t1.getLevel(),"t2 getLevel",t2.getLevel());
t1.setLevel(11);
console.log("t1 level:",t1.level,"t2 level",t2.level);
console.log("t1 getLevel:",t1.getLevel(),"t2 getLevel",t2.getLevel());

或者在Tank.prototype上有一个对象成员并改变它。

function Unit(){}
Unit.prototype.getLevel = function(){
    return this.shared.level+1;
};
Unit.prototype.setLevel = function(level){
    this.shared.level=level;
};
function Tank(){}
Tank.prototype = Object.create(Unit.prototype);
Tank.prototype.constructor=Tank;
Tank.prototype.shared={};
Tank.prototype.shared.level=5;
var t1 = new Tank();
var t2 = new Tank();
console.log("t1 level:",t1.shared.level,"t2 level",t2.shared.level);
console.log("t1 getLevel:",t1.getLevel(),"t2 getLevel",t2.getLevel());
t1.setLevel(11);
console.log("t1 level:",t1.shared.level,"t2 level",t2.shared.level);
console.log("t1 getLevel:",t1.getLevel(),"t2 getLevel",t2.getLevel());

有关构造函数和原型的更多信息,请访问:https://stackoverflow.com/a/16063711/1641941

<强>更新

演示继承实例特定和共享(原型)成员。函数通常在原型上,因为它对所有实例都是一样的。构造函数还可以初始化特定于实例的成员(例如damagePerSecond)。无需在Tank和AirDefense中初始化它,因为Unit可以处理它:

function Unit(args){
  this.damagePerSecond=args.damagePerSecond;
  //..bunch of other instance specific members
}

function Tank(){
  //Tank is a Unit so we can take all instance specific Unit members
  //inherit instance specific members from Unit
  Unit.call(this, {damagePerSecond:[2,3,4]});
}
//inherit shared members from Unit
//... Tank.prototype = Object.create(Unit.pro ... bla bla bla
var t = new Tank();
console.log(t.damagePerSecond);//=[2,3,4]

args是一个可以传递给构造函数的对象,我可以将它传递给Tank,Tank可以通过以下方式传递给Unit:

function Tank(args){
  args=args||{};//don't worry if no args are passed
  args.damagePerSecond=args.damagePerSecond||[2,3,4];//passed arg or default
  //... and a bunch of other stuff
  Unit.call(this,args);
}

var t = new Tank();//all defaults
var t1 = new Tank({damagePerSecond:[7,8,9]});//super Tank

当您有调用其他函数的函数时,使用这样的模式非常有用。当你定义像someFunction(who, what, when)这样的严格,并且你将拥有一长串函数时,如果需要在开头添加一个名为where的额外变量,那么你需要进行大量的输入。仅在最后使用。

我之前发布的链接涵盖了大部分内容。