如何在不调用它的情况下为JavaScript函数提供特定的上下文

时间:2012-12-07 17:21:11

标签: javascript oop closures

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

以下是一些代码:

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的背景是错误的。我想可能有一种方法可以使用调用或应用来解决这个问题。任何帮助都会摇滚!

3 个答案:

答案 0 :(得分: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()创建此classe的实例,所有这些实例都使用相同的函数hp(函数中的this引用实例)。

编辑

如果您想存储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());

答案 1 :(得分: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());

我没有对你正在做的其他事情的有效性提出任何要求,因为似乎有很多变量显示但没有考虑,但是你的封闭似乎是在错误的地方。

答案 2 :(得分: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/