【问题标题】:Using Object.assign() to assign a number results in the object reference being undefined使用 Object.assign() 分配数字会导致对象引用未定义
【发布时间】:2018-03-21 04:48:21
【问题描述】:

对于此处包含的大量代码,我深表歉意,但我想披露所有内容。无论我尝试什么,我都无法让Object.assign() 为给定的键分配一个整数,尽管相同的操作可以完美地在下一行分配一个浮点数。

此代码包含所有需要的引用,因此很笨拙(我的调试工具包的一部分):

let markers = []
let cumulativeTimes = {}

const randomWholeNumber = (min, max) => Math.floor(Math.random() * (max - min + 1) + min)

const time = (marker) => { markers[marker] = process.hrtime() }

const timeEnd = (marker, cumulative = true) => {
  const hrend = process.hrtime(markers[marker])
  const precision = 3
  const seconds = hrend[0] // already an int
  const milliSeconds = +(hrend[1] / 1000000).toFixed(precision) // unary plus converts string result to int

  console.log(`Seconds is ${seconds} with type ${typeof(seconds)}`) // outputs "number" - always!

  if (cumulative) {
    let mark = cumulativeTimes[marker]
    mark ? mark.s += seconds : Object.assign(cumulativeTimes, { [marker]: { s: seconds } } ) // <-- It's a trap!
    mark ? mark.ms += milliSeconds : Object.assign(cumulativeTimes, { [marker]: { ms: milliSeconds } } )
    mark = cumulativeTimes[marker]
    console.log(`${mark.s}s, ${mark.ms}ms -- ${marker}`) // outputs undefineds, then NaNs (for seconds)
  } else {
    console.log(`${seconds}s, ${milliSeconds}ms -- ${marker}`)
  }
}

const someLongOp = () => {
  time('someLongOp')
  return new Promise ( async (resolve) => {
    await setTimeout(timeEnd, randomWholeNumber(1000, 5000), 'someLongOp')
    resolve()
  })
}

const test = async (count) => {
  for (let i = 0; i < count; i++) {
    await someLongOp()
  }
}

test(2)

样本输出:

Seconds is 2 with type number
undefineds, 993.351ms -- someLongOp
Seconds is 3 with type number
NaNs, 1476.091ms -- someLongOp

现在我明白为什么第二个值是 NaN(因为在第二次运行 timeEnd() 时,“mark.s”键存在,但是它引用了值 undefined,并且对 undef 执行任何算术运算都会导致 NaN )。

我不明白为什么,当seconds 是一个简单的无符号整数且被确认为数字时,该值在timeEnd() 的第一次运行时未正确分配。更奇怪的是,正如我们从毫秒输出中看到的那样,这个完全相同的操作对于浮点数也能正常工作……尽管它们在技术上都是 double-precision 64-bit unsigned ints

cumulative 的默认值更改为false,秒数会按预期输出和显示,所以我有95% 的把握这是在Object.assign() 部分发生的事情。

一旦它符合条件,肯定会奖励它......期待了解地球上正在发生的事情!

【问题讨论】:

  • 呃,new Promise ( async (resolve) =&gt; {await setTimeout?这根本不是 Promise 的运作方式。
  • 如果marker 是一个字符串,不要将markers 设为一个数组。使用对象或地图。
  • 调试文件甚至没有进入回购,更不用说生产我的朋友了;)它充满了古怪的东西。别介意 - 你发现对象覆盖 - 谢谢!

标签: ecmascript-6 javascript-objects assign


【解决方案1】:

这与双精度数与整数无关。只是你的代码

mark ? mark.s += seconds : Object.assign(cumulativeTimes, { [marker]: { s: seconds } } ) // <-- It's a trap!
mark ? mark.ms += milliSeconds : Object.assign(cumulativeTimes, { [marker]: { ms: milliSeconds } } )

错了。让我们去糖吧:

if (mark)
   mark.s += seconds;
else
   cumulativeTimes[marker] = { s: seconds };
if (mark)
   mark.ms += milliSeconds;
else
   cumulativeTimes[marker] = { ms: milliSeconds };

这显然是行不通的,用s 属性覆盖具有ms 属性的对象。请记住,Object.assign 不会递归合并!

你真正想要的是

if (mark) {
    mark.s += seconds;
    mark.ms += milliSeconds;
} else {
    cumulativeTimes[marker] = {
        s: seconds,
        ms: milliSeconds
    };
}

【讨论】:

  • 我在那个兔子洞里走得太深了。解决了,谢谢
猜你喜欢
  • 2019-12-05
  • 2011-11-21
  • 1970-01-01
  • 1970-01-01
  • 2016-09-18
  • 2020-10-01
  • 1970-01-01
  • 2019-08-09
  • 2018-06-21
相关资源
最近更新 更多