使用 Object.assign() 分配数字会导致对象引用未定义
Using Object.assign() to assign a number results in the object reference being undefined
对于此处包含的大量代码,我深表歉意,但我想公开所有内容。无论我尝试什么,我都无法 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()
部分发生了一些事情。
一旦符合条件,肯定会为此悬赏...期待了解到底发生了什么!
这与双精度与整数无关。只是你的代码
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
};
}
对于此处包含的大量代码,我深表歉意,但我想公开所有内容。无论我尝试什么,我都无法 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()
部分发生了一些事情。
一旦符合条件,肯定会为此悬赏...期待了解到底发生了什么!
这与双精度与整数无关。只是你的代码
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
};
}