这段代码中发生了什么, Number 对象持有属性并增加了数字?

新手上路,请多包涵

最近的一条推文 包含这段 JavaScript。

有人可以逐步解释其中发生的事情吗?

 > function dis() { return this }
undefined
> five = dis.call(5)
Number {[[PrimitiveValue]]: 5}
> five.wtf = 'potato'
"potato"
> five.wtf
"potato"
> five * 5
25
> five.wtf
"potato"
> five++
5
> five.wtf
undefined
> five.wtf = 'potato?'
"potato?"
> five.wtf
undefined
> five
6

特别是,我不清楚:

  • why the result of dis.call(5) is a Number with some kind of a [[PrimitiveValue]] property, but the results of five++ and five * 5 似乎只是纯数字 525 (不是 Number s)
  • 为什么 five.wtf 属性在 five++ 增量后消失
  • 为什么 five.wtf 属性在 five++ 增量之后甚至不再可设置,尽管 five.wtf = 'potato?' 分配显然设置了值。

原文由 Nathan Long 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 290
2 个回答

OP在这里。在 Stack Overflow 上看到这个很有趣 :)

在逐步执行该行为之前,澄清几件事很重要:

  1. 数字值数字对象a = 3 vs a = new Number(3) )非常不同。一个是原语,另一个是对象。您不能将属性分配给基元,但可以分配给对象。

  2. 两者之间的强制是隐含的。

例如:

    (new Number(3) === 3)  // returns false
   (new Number(3) == 3)   // returns true, as the '==' operator coerces
   (+new Number(3) === 3) // returns true, as the '+' operator coerces

  1. 每个 表达式 都有一个返回值。当 REPL 读取并执行一个表达式时,这就是它显示的内容。返回值通常并不意味着您的想法,而是暗示不正确的事情。

好的,我们开始吧。

JavaScript 代码的原始图像

誓言。

 > function dis() { return this }
undefined
> five = dis.call(5)
[Number: 5]

定义一个函数 dis 并用 5 调用 它。这将以 5 作为上下文( this )执行函数。这里它从一个数字值被强制转换为一个数字对象。非常重要的是要注意,如果我们处于 严格模式 ,就不会发生这种情况

 > five.wtf = 'potato'
'potato'
> five.wtf
'potato'

现在我们将属性 five.wtf 设置为 'potato' ,并以 5 作为对象,果然它接受了 Simple Assignment

 > five * 5
25
> five.wtf
'potato'

five 作为对象,我确保它仍然可以执行简单的算术运算。它可以。它的属性仍然存在吗?是的。

轮到。

 > five++
5
> five.wtf
undefined

现在我们检查 five++后缀递增 的技巧是整个表达式将根据原始值求值 ,然后 递增该值。它看起来像 five 仍然是五,但实际上表达式评估为五,然后设置 five6

不仅 five 被设置为 6 ,而且它被强制变回数字值,并且所有属性都丢失了。由于基元不能保存属性, five.wtf 未定义。

 > five.wtf = 'potato?'
'potato?'
> five.wtf
undefined

我再次尝试将属性 wtf 重新分配给 five 。返回值暗示它会粘住,但实际上不会,因为 five 是一个数字值,而不是一个数字对象。该表达式的计算结果为 'potato?' ,但是当我们检查时我们发现它没有被分配。

声望。

 > five
6

自从后缀增量以来, five 一直是 6

原文由 Matthew 发布,翻译遵循 CC BY-SA 4.0 许可协议

有两种不同的方式来表示数字:

 var a = 5;
var b = new Number(5);

第一个是原语,第二个是对象。对于所有意图和目的,两者的行为相同,除了它们在打印到控制台时看起来不同。一个重要的区别是,作为一个对象, new Number(5) 接受新属性就像任何普通的 {} ,而原始 5

 a.foo = 'bar';  // doesn't stick
b.foo = 'bar';  // sticks

至于最开始的 dis.call(5) 部分,请看 How does the “this” keyword work? .假设 call this 值,并且此操作强制将数字变为更复杂的 Number object form2727。 * 后来 ++ 强制它回到原始形式,因为加法运算 + 产生一个新的原始形式。

 > five = dis.call(5)  // for all intents and purposes same as new Number(5)
Number {[[PrimitiveValue]]: 5}
> five.wtf = 'potato'
"potato"
> five.wtf
"potato"

Number 对象接受新属性。

 > five++

++ 产生一个新的原语 6 值…

 > five.wtf
undefined
> five.wtf = 'potato?'
"potato?"
> five.wtf
undefined

…没有也不接受自定义属性。

\* 请注意,在 _严格模式下_, this 参数将被区别对待, 不会 被转换为 Number 。有关实施细节,请参阅 http://es5.github.io/#x10.4.3

原文由 deceze 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题