0

我想创建一个带有一些隐藏(使用闭包)变量的对象,以及利用这些隐藏变量的方法。但是,我不想为每个实例重新创建这些方法。我想让它们记住一次。我正在使用普通函数来实例化对象。

这是一些代码:

function Mario () {
  var mario = {}; // create the obj
  mario.name = "Mario"; // create a property on it
  mario.hp = (function () { // set up a closure
    var currentHp = Mario.baseHp * 100; // create a "hidden" variable
    return function (value) { // return the hp function that utilizes the hidden currentHp variable
      if (!!value) {
        return currentHp = ((currentHp * Mario.baseHp) + value);
      }
      return currentHp * Mario.baseHp;
    };
  }());
  return mario; // send along the newly created object
}
Mario.baseHp = 1;

var mario = Mario();
log(mario);
log(mario.hp());
log(mario.hp(-20));
log(mario.hp());

这里的问题是,每次我创建另一个“mario”对象时,我都会在内存中再次创建 hp 函数。到目前为止,这是我对解决方案的尝试:

function Mario () {
  var mario = {}; // create the obj
  mario.name = "Mario"; // create a property on it
  mario.hp = (function () { // set up a closure
    var currentHp = Mario.baseHp * 100; // create a "hidden" variable
    return Mario.hp; // reference the hp function below..... but the context is wrong, it needs access to currentHp variable.
  }());
  return mario; // send along the newly created object.
}
Mario.baseHp = 1;
Mario.hp = function (value) { // Create the hp function once in memory
  if (!!value) {
    return currentHp = ((currentHp * Mario.baseHp) + value);
  }
  return currentHp * Mario.baseHp;
};
var mario = Mario();
log(mario);
log(mario.hp());
log(mario.hp(-20));
log(mario.hp());

但显然 Mario.hp 的上下文是错误的。我在想可能有一种方法可以使用 call 或 apply 来解决这个问题。任何帮助都会摇滚!

4

3 回答 3

3

通常的解决方案是使用原型和新的:

function Mario () {
  this.name = "Mario"; // create a property on it
  this.baseHP = 33;
}
Mario.prototype.hp = function () { 
    var currentHP = this.baseHp * 100;
    ...
};

var mario = new Mario();
log(mario);
log(mario.hp());
log(mario.hp(-20));
log(mario.hp());

这创建了通常称为类的东西Mario。使用new Mario()创建此类的实例,它们都使用相同的函数hpthis在函数中引用实例)。

编辑

如果要存储currentHP变量和hp返回它的函数,只需执行以下操作:

function Mario () {
  this.name = "Mario"; // create a property on it
  this.baseHP = 33;
  this.currentHP = this.baseHp * 100;
}
Mario.prototype.hp = function () { 
    return this.currentHP;
};

var mario = new Mario();
log(mario);
log(mario.hp());
于 2012-12-07T17:26:19.467 回答
1

我认为所有这些关于原型的讨论都是多余的,对你的情况并没有那么大的帮助。您在这里并不真正需要原型,因为您的所有实例Mario都将为currentHp. 同样,您无需创建Mario真正的构造函数并担心必须记住new关键字(尽管您可以根据需要)。

据我所知,您尝试做的所有事情都可以通过闭包来处理,另外还可以让您的私人成员(比如baseHP计算 HP 的逻辑)真正私有。尝试这个:

var Mario = (function () {
    //"private" variable encapsulated by the closure
    var baseHp = 1;

    //"private" method for calculating HP given an instance's current HP
    var getHp = function (currentHp, value) {
        return currentHp * Enemy.baseHp + (value || 0);
    };

    //in OOP terms, baseHp and getHp would be like private static members used by
    //the whole class.

    return function () {
        //another "private" variable, but this one is only for 
        //the current instance.
        var currentHp = baseHp * 100;

        //instance:
        return {
            name: "Mario",
            hp: function (value) {
                return !!value
                    ? currentHp = getHp(currentHp, value)
                    : getHp(currentHp);
            }
        };
    };
})();

我已经在控制台中对此进行了测试,它似乎工作正常:

//test
var Enemy = {
    baseHp: 3
};
var log = console.log.bind(console);
var mario = Mario(); //or new Mario(); either one is fine
log(mario);
log(mario.hp());
log(mario.hp(-20));
log(mario.hp());

在 jsFiddle 上试用:http: //jsfiddle.net/jmorgan123/zkw2P/

于 2012-12-07T18:30:13.110 回答
1
var Mario = (function() {
  var name = "Mario"; 
  var hp = function (value) { 
      var currentHp = baseHp * 100; 
      if (!value) {
          return currentHp = ((currentHp * Enemy.baseHp) + value);
      }
      return currentHp * Enemy.baseHp;
  }
  return {
        name:name,
        hp:hp
  }
})();
console.log(Mario);
console.log(Mario.hp());
console.log(Mario.hp(-20));
console.log(Mario.hp());

我对你所做的其他事情的有效性不做任何声明,因为似乎有很多变量显示但没有考虑,但你的外壳似乎在错误的地方。

于 2012-12-07T17:38:44.020 回答