【问题标题】:How to create a reusable function with different variables in javascript如何在javascript中创建具有不同变量的可重用函数
【发布时间】:2015-02-28 14:25:12
【问题描述】:

我正在使用 javascript/html 开发游戏。我有很多按钮,它们都使用相同的功能,但里面的值不同。

我有 32 个按钮,这意味着 32 个函数,这些函数的作用完全相同,只是它们使用不同的变量/值。

我正在考虑使用对象/数组,并在对象中放置一个函数,然后重用它来更改其变量,但我不知道这是否可能,或者这是一个好主意。

我还是新手。这些按钮用于“攻击”怪物,每个按钮都不同,即“统计/健康/伤害”。

我的按钮名为“attack1/attack2/”,功能为“attack1/attack2”。每次我想添加怪物时,我都会复制整个函数并更改其值,这并不难,但考虑到我想更改伤害公式,我需要更改所有 32 个函数,这不是我想做的。

我已经创建了一个对象,我在其中使用数组存储所有怪物数据。

最后,我不是以英语为母语的人,如果您看不懂我,请见谅。让我知道是否有任何方法可以帮助您更好地理解它。

谢谢

var monsterStats = {
killed: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0],

hp: [10, 30, 70, 130, 190, 280, 380, 500, 700, 900, 1300, 1600, 2200, 2600,
3000, 4000, 5000, 7000, 9000, 12000, 15000, 18000, 22000, 28000, 34000, 40000,
48000, 570000, 65000, 72000, 80000, 88000],

maxHp: [10, 30, 70, 130, 190, 280, 380, 500, 700, 900, 1300, 1600, 2200,
2600, 3000, 4000, 5000, 7000, 9000, 12000, 15000, 18000, 22000, 28000, 34000,
40000, 48000, 570000, 65000, 72000, 80000, 88000],

def: [0, 2, 4, 6, 9, 13, 18, 25, 30, 38, 45, 53, 65, 75, 88, 95, 120, 140,
170, 200, 220, 250, 300, 400, 500, 700, 1000, 1200, 2000, 2500, 3000],

minDmg: [2, 2, 4, 6, 9, 13, 18, 25, 32, 40, 50, 60, 75, 86, 96, 105, 140,
160, 200, 230, 260, 290, 350, 420, 500, 900, 1200, 1700, 2500, 3200, 4500,
6000],

maxDmg: [3, 5, 7, 10, 14, 19, 23, 30, 37, 45, 58, 67, 80, 92, 100, 110,
160, 185, 215, 250, 275, 320, 380, 550, 700, 1200, 1500, 2200, 3000, 4000,
5500, 8000],

baseExp:[5, 10, 30, 50, 90, 140, 190, 260, 340, 450, 560, 700, 810, 940,
1060, 1200, 1600, 2150, 2600, 3400, 5000, 7000, 10000, 15000, 23000, 35000,
70000, 120000, 180000, 290000, 430000, 680000, 1000000]

};

function attack(number) {
if (monsterStats.hp[0] >= 1) {
    var damage = Math.floor(Math.random() * (maxdamage - mindamage + 1)) +
        mindamage;
    damage = Math.floor(damage - monsterStats.def[0] * 1.2);
    if (damage > 1) {
        monsterStats.hp[0] -= damage;
        document.getElementById("hp1").innerHTML = monsterStats.hp[0];
        Log("You deal " + damage + " <span style=\"color:blue\">damage</span>");
    } else Log("<span style=\"color:blue\">Enemy block your attack! </span>");
    var dmg = Math.floor(Math.random() * (monsterStats.maxDmg[0] - monsterStats.minDmg[0] + 1)) + monsterStats.minDmg[0];
    dmg = Math.floor(dmg - defense * 1.2);
    if (dmg > 1) {
        health = health - dmg;
        document.getElementById("health").innerHTML = health;
        Log("Enemy hit you for " + dmg + " <span style=\"color:red\">damage</span>");
    } else Log("<span style=\"color:green\">You blocked enemy attack! </span>");
    if (health < 1) {
        monsterStats.hp[0] = monsterStats.maxHp[0];
        health = maxhealth;
        document.getElementById("hp1").innerHTML = monsterStats.hp[0];
        document.getElementById("health").innerHTML = health;
        Log("<span style=\"color:blue\">You have lost!</span>");
    }
    if (monsterStats.hp[0] < 1) {
        monsterStats.killed[0] = monsterStats.killed[0] + 1;
        monsterStats.hp[0] = monsterStats.maxHp[0];
        document.getElementById("hp1").innerHTML = monsterStats.hp[0];
        document.getElementById("kills1").innerHTML = monsterStats.killed[0];
        var expgain = monsterStats.baseExp[0] / (level / 5);
        if (experience < maxexperience) {
            experience = Math.floor(experience + expgain);
            if (experience >= maxexperience) {
                level += 1;
                stats += 2;
                experience = experience - maxexperience;
                maxexperience = Math.floor(maxexperience * 1.2);
                Log("You leveled up! Your current level is: " + level);
                document.getElementById("maxexperience").innerHTML = maxexperience;
                document.getElementById("level").innerHTML = level;
                document.getElementById("stats").innerHTML = stats;
                document.getElementById("experience").innerHTML = experience;
            } else Log("You gain: " + Math.floor(expgain) + "experience!");
            document.getElementById("experience").innerHTML = experience;
        }
        var goldLog = 0;
        var golddrop = Math.floor((Math.random() * 100) + 1);
        if (golddrop > 95) {
            golddrop = Math.floor((Math.random() * 20) + 1);
            gold = gold + golddrop;
            Log("You loot: " + golddrop + "gold!");
            document.getElementById("gold").innerHTML = gold;
        } else if (golddrop >= 75) {
            golddrop = Math.floor((Math.random() * 10) + 1);
            gold = gold + golddrop;
            Log("You loot: " + golddrop + "gold!");
            document.getElementById("gold").innerHTML = gold;
        } else if (golddrop >= 60) {
            golddrop = Math.floor((Math.random() * 5) + 1);
            gold = gold + golddrop;
            Log("You loot: " + golddrop + "gold!");
            document.getElementById("gold").innerHTML = gold;
        }
        "This is <span style=\"color:red\">RED</span> text.";
        var itemdrop = Math.floor((Math.random() * 100) + 1);
        if (itemdrop < 33) {
            var fusiondrop = Math.floor((Math.random() * 100) + 1);
            if (fusiondrop < 70) {
                common = common + 1;
                Log("You loot:<span style=\"color:grey\">Common</span> Fusion stone!");
                document.getElementById("common").innerHTML = common;
            } else if (fusiondrop <= 100) {
                rare = rare + 1;
                Log("You loot:<span style=\"color:blue\">Rare</span> Fusion stone!");
                document.getElementById("rare").innerHTML = rare;
            }
        } else if (itemdrop < 66) {
            var expdrop = Math.floor((Math.random() * 100) + 1);
            if (expdrop < 70) {
                commonexp = commonexp + 1;
                Log("You loot:<span style=\"color:grey\">Common</span> Exp orb!");
                document.getElementById("commonexp").innerHTML = commonexp;
            } else if (expdrop <= 100) {
                rareexp = rareexp + 1;
                Log("You loot:<span style=\"color:blue\">Rare</span> Exp orb!");
                document.getElementById("rareexp").innerHTML = rareexp;
            }
        } else {
            var golddrop = Math.floor((Math.random() * 100) + 1);
            if (golddrop < 70) {
                commongold = commongold + 1;
                Log("You loot:<span style=\"color:grey\">Common</span> Gold orb!");
                document.getElementById("commongold").innerHTML = commongold;
            } else if (golddrop <= 100) {
                raregold = raregold + 1;
                Log("You loot:<span style=\"color:blue\">Rare</span> Gold orb!");
                document.getElementById("raregold").innerHTML = raregold;
            }
        }
    }
}

}

这是代码的一部分,我用了这个代码 32 次。

【问题讨论】:

  • 这就是函数参数的用途。
  • 正是@Barmar 所说的。您可以将其简化为 attack(1);attack(2);,而不是使用 attack1()attack2()
  • 您可以拥有一个名为attack(id) 的函数,当用户单击button1 时,通过传递适当的idattack(1) 来调用该函数。让attack 函数内的代码创建一个monster 并将其添加到全局数组array.push(monster)。说了这么多,请贴出相关的代码,你试过的,以便更正和改进..
  • 嘿,谢谢你的回答,我把代码放在我的问题中。我不确定我为什么要使用array.push(monster)。如果我的代码可以帮助您理解我的问题,请告诉我。

标签: javascript arrays performance function javascript-objects


【解决方案1】:

假设您像这样创建了一个Monster“对象”数组:

var Monsters = {
    "foo": {"name":"Foo the foot", "hp":125, "power":3},
    "bar": {"name":"Barbarian the bar", "hp":25, "power":9001}
};

你也可以编写你的按钮标记,这样每个按钮都可以与一个怪物相关联。例如:

<button rel="attack" data-monster_id="foo">Attack</button>
<button rel="attack" data-monster_id="bar">Attack</button>

现在,您可以将它们与类似的东西联系起来:

var btns = document.querySelectorAll('button[rel="attack"]');
for (var i=0; i<btns.length; i++) {
    this.addEventListener('click', function(){
        attack(this.dataset.monster_id);
    }, false);
}

最后,假设attack 方法如下:

function attack(id) {
    Monsters[id].hp -= currentDamage;
    // whatever consequences the attack may have
}

希望这能给您带来灵感并祝您的游戏好运 :)

【讨论】:

  • 嘿,我会考虑使用这个,如果我在我的代码中出现一些错误之前弄清楚这段代码是如何工作的。感谢您的回答。
  • 从我之前的经验来看,快就是慢,慢就是快。我的意思是,如果你真的花时间来创建你的架构,它会很好,当你的代码变得更大的时候你不会后悔。一个常见的错误是试图同时做所有事情,而代码太短以至于无法扩展。
  • 嘿,我明白 :) 这就是为什么我决定在代码不多的情况下更改它,至少没有我以后想添加的那么多。
【解决方案2】:

不确定您的意思,但我认为使用 event delegation 可能有助于重用函数。在 sn-p 示例中,data-* 属性用于存储带有按钮的分数。此外,事件委托使您能够创建新按钮而无需分配新的处理程序。

document.querySelector('#testbuttons').addEventListener('click', testdemo);
document.querySelector('#testcreate').addEventListener('click', newbttn);

// handler for all buttons within div#testbutton
function testdemo(e) {
  var from = e.target || e.srcElement
     ,score = from.getAttribute('data-score')
     ,kills = JSON.parse(from.getAttribute('data-kills'));
  if (!score) { return true; }
  Helpers.log2Screen('score clicked button: ', score, 
                     ', kills: <code>[', kills, ']</code>',
                      {clear: true});
}

function newbttn() {
  var score = Math.floor(1+Math.random()*200);
  document.querySelector('#testbuttons').innerHTML +=
    '<br><button data-score="'+score+'" data-kills="[]">button '+score+'</button>';
  Helpers.log2Screen('Created new button with score ', score, {clear: true});
}
button {
  margin-top: 3px;
}
<!-- a few helpers -->
<script src="http://kooiinc.github.io/JSHelpers/Helpers-min.js"></script>

<div id="result"><p>Awaiting action ...</p></div>
<div id="testbuttons">
  <button data-score="12" data-kills="[2,5,3]">bttn 12</button><br>
  <button data-score="122" data-kills="[0,2,8]">bttn 122</button>
</div>

<button id="testcreate">create new button</button>

【讨论】:

  • 嘿,谢谢你的回答,但我是新手,你的代码对我来说太复杂了:/我理解其中的一些,但我不知道我将如何实际使用它我的代码。仍然感谢您的回答。
  • 读了几遍后,我或多或少地理解了它是如何工作的,但在我的例子中,我的按钮遍布整个 html 页面,所以我不确定是否可以将它们放在里面“ div id =“testbuttons”。在那种情况下,我将不得不创建更多的“querySelectors”,这意味着更多的功能,对吗?仍然可以让我使用更少的代码,我会考虑使用你的方法,如果有其他方法不适合我,再次感谢。或者实际上,我可以在不同的地方使用相同的 div id 对吗?那可能对我有用,但我需要一种方法来根据我按下的按钮更改函数变量。
  • 如果您不能使用事件委托,那么想法的另一半——使用data-* 属性将内容存储在按钮元素中——仍然可以让您仅重用一个功能。见developer.mozilla.org/en-US/docs/Web/Guide/HTML/…
  • 感谢您的链接,我会检查一下。
  • 顺便说一下,如果按钮分散在页面上,您可以将事件处理分配给document.body。 sn-p 中的方法testdemo 不会阻止这种情况,它仅在找到data-score 属性时运行。
【解决方案3】:

我认为您正在寻找这样的东西:

function createAttack1(damage) {
    return function() {
        ... Your attack1 logic using 'damage'
    }
}

然后你可以用它来连接你的按钮:

button1.addEventListener("click", createAttack1(5));
button2.addEventListener("click", createAttack1(10));
button3.addEventListener("click", createAttack1(15));

这允许您重复使用相同的核心逻辑,同时拥有不同的统计数据,而无需您一直在做的所有复制/粘贴。

【讨论】:

  • 嘿,我是 javascript 新手,你能告诉我,你如何将“monster2”添加到函数中?以及如何更改该函数内的实际值?让我们参与我的功能monsterStats.hp[0] -= damage; 我怎样才能更改 hp[0] 并改用 hp[1]?
  • 这篇文章值得一看:developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures 一旦你理解了闭包/包装器的概念,你应该可以做你想做的事了。
  • 我有一个问题,addEventListener 你添加“creatureAttack1(5)...如果我有“函数 creativeAttack1(myObject.kills[], myObject.hp[]) 是这样的可能吗?所以我可以更改 addEventListener 并同时更改所有值?
  • 是的。您可以拥有任意数量的参数。正如其他人所提到的,我建议更改存储怪物数据的方式。你有代表 32 个怪物的 kills[32]、hp[32] 等。您将数据以列格式存储,这更难以理解和管理。将数据更改为具有怪物对象数组的行格式: monsters.push({killed: 0, hp: 10, maxHp: 10, ... });这样,您可以简单地传递一个怪物数据对象。连接按钮时也会让事情变得更容易。
  • so 而不是 var = {monster:[1, 2, 3, 4], hp:[10, 20, 30, 40]} (第一个怪物,即“第一个按钮”,而是存储单个对象中的每个怪物?比如 var monster1 = {kill:0, hp:10, maxhp:10}, var monster2 = {kill:0, hp:20, maxhp:20} 类似的东西?但是,我将如何做一个函数参数?如果我使用不同的对象,我不能做“函数 bioAttack1(monster1 object) 那么怪物 2 呢?等等那个 button1.addEventListener,“button1”是按钮 id?和“click”只是某种功能,这意味着我点击一个按钮?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-02
  • 2015-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-23
  • 2018-07-19
相关资源
最近更新 更多