即使值存在,属性返回undefined ......?

时间:2018-03-28 04:38:14

标签: javascript

我有这个对象resources

var resources = { //Handles resources of all kinds.
    number: 100,
    money: 23000000,
    science: 1000,
    popularity: {
        amount: 0,
        upgProd: 0 //Amount produced from upgrades.
    }

};

这看起来像普通对象。 但是,我正在尝试显示一定数量popularity。每当我尝试显示它时,我会得到NaN而不是数字。 我尝试返回console.log(resources.popularity.upgProd);但我仍然得到undefined。我不知道为什么因为我定义变量但我仍然未定义... 在我的console.log()时,只有undefined在IDE或控制台中没有错误。

编辑:这是一些周围的上下文...这是我的update函数,每1/7秒更新一次。此外,resources.popularity.upgProd的第一个值为0,然后下一个值为NaN。

function update() {
buffer++;
if (buffer == 35) {
checkVisibilityOnBuildings();
checkVisiblityOnUpgrades();
checkVisibilityOnResources();
buffer = 0;
} // Every 5 seconds (35 ticks) visibility will be checked and updated.

    /* Number increasing. A bit tedious but no other way to do it yet. */
    resources.number += 
   ((BUILDINGS[0].numProdBase * BUILDINGS[0].count) + //Now it's easy! Just do UPGRADES[n+1] for the next building.
    (BUILDINGS[1].numProdBase * BUILDINGS[1].count) +
    (BUILDINGS[2].numProdBase * BUILDINGS[2].count) +
    (BUILDINGS[3].numProdBase * BUILDINGS[3].count));
    //Science gained per tick. Var used to make the "scienceProductionTotalDisp" work properly
    var scienceTotalPerTick = 
    (BUILDINGS[2].sciProdBase * BUILDINGS[2].count) + 
    (BUILDINGS[3].sciProdBase * BUILDINGS[3].count);

    resources.science += scienceTotalPerTick;



    //Display vars for html so that rounding errors don't happen.
    var numDisp = Math.floor(resources.number);
    var sciDisp = Math.floor(resources.science * 100) / 100;
    var popDisp = Math.floor(resources.popularity.amount * 100) / 100;
    console.log(Number(resources.popularity.upgProd));
    var moneyTotalPerTick = Math.pow(resources.number, (1/(player.moneyRatio))) + 1; //Cash flow per 143ms (7n for total / sec ish)
    var popularityTotalPerTick = (Number(resources.popularity.upgProd)) + 0;
    resources.popularity += popularityTotalPerTick;
    console.log(resources.popularity.upgProd);
    resources.money += moneyTotalPerTick;
    getId('moneyProductionTotalDisp').innerHTML = numFormat(Math.floor(moneyTotalPerTick * 7));
    getId('moneyDisp').innerHTML = numFormat(Math.round(resources.money * 100) / 100);
    getId('numberDisp').innerHTML = numFormat(numDisp);
    getId('scienceDisp').innerHTML = numFormat(sciDisp);
    getId('popularityDisp').innerHTML = numFormat(popDisp);
    getId('scienceProductionTotalDisp').innerHTML = 
numFormat(Math.floor(scienceTotalPerTick * 700) / 100);
    getId('popularityProductionTotalDisp').innerHTML = 
numFormat(Math.floor(popularityTotalPerTick * 700) / 100);

谢谢!

2 个答案:

答案 0 :(得分:1)

这是你的问题:

resources.popularity += popularityTotalPerTick;

受欢迎程度是一个对象,并不能做你想做的事。

由于您使用由值添加的对象的结果覆盖它,因此您将其分配为字符串[object Object]9,其中最后一位数字是popularTotalPerTick中的任何内容。

由于您在NaN中使用Number(x),因此获得console.log(Number(resources.popularity.upgProd));(非数字)。你为什么这样做?

每次调用函数时,getId是否都会在dom中查找元素?是否更改了对象,或者您是否每秒7次查询相同元素的DOM?

<小时/> 关于代码中其他内容的一些想法:

resources.number +=
    ((BUILDINGS[0].numProdBase * BUILDINGS[0].count) +
        (BUILDINGS[1].numProdBase * BUILDINGS[1].count) +
        (BUILDINGS[2].numProdBase * BUILDINGS[2].count) +
        (BUILDINGS[3].numProdBase * BUILDINGS[3].count));

我假设BUILDINGS是一个包含所有建筑物的阵列,并且您想要计算阵列中所有建筑物的数量。有一个函数:reduce有两个参数:一个函数和一个起始值:

resources.number += // do you really want += here and not just = ?
  BUILDINGS.reduce( (sum, item) => sum + (item.numProdBase * item.count), 0 );

如果您不熟悉箭头功能,可以将其替换为:

function (sum, item) { return sum + (item.numProdBase * item.count) }
var scienceTotalPerTick = 
    (BUILDINGS[2].sciProdBase * BUILDINGS[2].count) + 
    (BUILDINGS[3].sciProdBase * BUILDINGS[3].count);

我不确定为什么你只为两座建筑物而不是为所有建筑物而做,但你也可以在这里使用reduce,slice

var scienceTotalPerTick =
  BUILDINGS.slice(2,4).reduce( (sum, item) => sum + (item.sciProdBase * item.count), 0);

请注意,要切片的参数是开始 end end not included ),因此2,4给出了元素2和3 。

这部分代码......

getId('moneyProductionTotalDisp').innerHTML = numFormat(Math.floor(moneyTotalPerTick * 7));
getId('moneyDisp').innerHTML = numFormat(Math.round(resources.money * 100) / 100);
getId('numberDisp').innerHTML = numFormat(numDisp);
getId('scienceDisp').innerHTML = numFormat(sciDisp);
getId('popularityDisp').innerHTML = numFormat(popDisp);

我假设 getId 是一个通过 document.getElementById document.querySelector 获取元素的函数,并且你这样做是为了每一帧,你每次都得到相同的元素。现在假设元素是一个盒子,我要求你从世界另一端的仓库中获取它。当您交付盒子时,我打开盒子,更换内容并将其发回世界另一端的仓库。当你回来时,我要求你再次获得同样的盒子,你现在必须再次前往世界的另一端......当你回来时,故事重复......

我的观点是,每次前往世界的另一端获取相同的盒子,或者在每次更新时从DOM获取相同的元素是非常浪费的。您可以在开始更新之前通过查找一次来缓存元素,并且可以将结果放在对象中:

function getElementsToUpdate() {
  return {
    moneyProductionTotalDisp: getId('moneyProductionTotalDisp'),
    moneyDisp: getId('moneyDisp'),
    // and so on...
  }
}

如果将对象中的属性命名为与id相同,则可以将所有名称放在数组中,然后将其减少为对象。这样可以省去一些打字,而且由于拼写错误的名字很难找到错误:

function getElementsToUpdate() {
  return [
    'moneyProductionTotalDisp',
    'moneyDisp',
    'numberDisp',
    'scienceDisp',
    'popularityDisp',
    // and so on....
  ].reduce(
    (out, id) => { out[id] = getId(id); return out; }, {}
  )
}

注意:此功能应在启动时运行一次,而不是每次更新帧。它返回一个带有元素的对象。

在代码的某处,我假设您使用setInterval来调用更新功能。由于 setInteval 可以获取将被赋予被调用函数的额外参数,因此您可以执行以下操作:

var timerHandle = setInterval( update, 1000/7, getElementsToUpdate() );

更新是您的功能, 1000/7 为您提供每秒7次的间隔,而 getElementsToUpdate 是制作的功能从DOM 一个时间获取元素的耗时费用。

您需要更改更新功能以获取参数(名称不重要,但应该简短且具有描述性,因此我使用 elem )。这是 getElementsToUpdate()返回的所有html元素的对象。

function update(elem) {
  // ... your code ....

  // Old code, that makes an expensive lookup into the DOM, and start a HTML parser.
  // getId('numberDisp').innerHTML = numFormat(numDisp);

  // New code, that gets the pre-looked up element and set the text.  
  elem.numberDisp.textContent = numFormat(numDisp);
}

<小时/> 我没有使用 .innerHTML 的粉丝,因为它不是插入的html。如果不是html,请始终使用 .textContent 。在这种情况下,如果您使用output - 元素并设置 .value 属性会更好。

答案 1 :(得分:0)

尝试使用console.log(resources["popularity"]["upgProd"])