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());

ここでの問題は、別の「マリオ」オブジェクトを作成するたびに、メモリ内に 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

通常の解決策は、prototype と new を使用することです。

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());

これにより、通常クラスと呼ばれるものが作成されますMarionew Mario()このクラスの作成インスタンスを使用して、それらすべてが同じ関数を使用します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());
于 2012-12-07T17:26:19.467 に答える
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 に答える
1

プロトタイプに関するこの議論はすべてやり過ぎであり、実際にはあなたの状況に役立つものではないと思います。Marioのすべてのインスタンスが に対して独自の値を持つことになるため、ここではプロトタイプは実際には必要ありませんcurrentHp。同様に、真のコンストラクターを作成する必要はなく、キーワードMarioを覚えておく必要があることを心配する必要はありません (ただし、必要に応じて作成できます)。new

私が知る限り、あなたがやろうとしていることはすべてクロージャーによって処理でき、プライベート メンバー ( baseHPHP を計算するためのロジックなど) を真にプライベートに保つという追加のボーナスがあります。これを試して:

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 に答える