当前位置: 首页 > 知识库问答 >
问题:

Number对象保存属性并递增数字,这段代码中发生了什么?

危钱明
2023-03-14

最近的一条推文包含了这段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

特别是,我不清楚:

    < li >为什么< code>dis.call(5)的结果是具有某种< code>[[PrimitiveValue]]属性的< code>Number,而< code>five 和< code>five * 5的结果似乎只是普通的数字< code>5和< code>25(而不是< code>Number) < li >为什么< code>five.wtf属性在< code>five 递增后消失 < li >为什么< code>five.wtf属性在< code>five 增量之后不再可设置,尽管< code>five.wtf = 'potato?赋值显然设置了值。

共有3个答案

姚向晨
2023-03-14

爪哇脚本世界中有胁迫 - 侦探故事

内森,你不知道你发现了什么。

我已经调查了几个星期了。这一切都始于去年10月的一个暴风雨之夜。我偶然发现了<code>Number

我没有为接下来要发现的事情做好准备。

事实证明,JavaScript在没有告诉您的情况下,一直在您眼皮底下将您的数字更改为对象,将您的对象更改为数字。

JavaScript本来希望没有人会理解,但人们一直在报告奇怪的意外行为,现在感谢你和你的问题,我有了我需要的证据,可以将这件事公开。

这就是我们到目前为止发现的。我不知道我是否应该告诉你这个——你可能想关闭你的JavaScript。

> function dis() { return this }
undefined

当您创建该函数时,您可能不知道接下来会发生什么。一切看起来都很好,一切都很好 - 现在。

没有错误消息,只有控制台输出中的“未定义”一词,完全符合您的预期。毕竟,这是一个函数声明 - 它不应该返回任何东西。

但这只是开始。接下来发生了什么,谁也无法预测。

> five = dis.call(5)
Number {[[PrimitiveValue]]: 5}

是的,我知道,你期望一个5,但这不是你得到的,是它 - 你得到了别的东西 - 不同的东西。

同样的事情也发生在我身上。

我不知道该怎么做。它把我逼疯了。我睡不着,吃不下,我试着把它喝掉,但是再多的山露也不会让我忘记。它就是没有任何意义!

就在那时,我发现了到底发生了什么-这是强迫,它就在我眼前发生,但我太盲目了,看不见它。

Mozilla试图通过将其放在他们知道没有人会看的地方来埋葬它 - 他们的文档。

经过几个小时的反复阅读,我发现了这个:

"…原始值将被转换为对象。"

它就在那里,可以用Open Sans字体拼写出来。这是call()函数-我怎么会这么笨?!

我的号码根本不再是一个数字。当我把它传递给call()的那一刻,它变成了别的东西。它变成了……一个对象。

起初我简直不敢相信。这怎么可能是真的呢?但我不能忽视我周围越来越多的证据。如果你只是看一下,它就在那里:

> five.wtf = 'potato'
"potato"

> five.wtf
"potato"

趾铁是对的。数字不能具有自定义属性 - 我们都知道这一点!这是他们在学院教你的第一件事。

我们应该在看到控制台输出的那一刻就知道了——这不是我们所想的数字。这是一个冒名顶替者——一个冒充我们可爱的无辜数字的物体。

这是…新的数字(5)

答案是肯定的!这很有道理。call()有一个工作要做,他必须调用一个函数,要做到这一点,他需要填充这个,他知道他不能用一个数字来做那个 - 他需要一个对象,他愿意做任何事情来得到它,即使这意味着强制我们的数字。当 call() 看到数字 5 时,他看到了一个机会。

这是一个完美的计划:等到没有人看的时候,把我们的号码换成一个看起来像它的东西。我们得到一个数字,函数被调用,没有人会更聪明。

这确实是一个完美的计划,但是就像所有的计划一样,即使是完美的计划,也有一个漏洞,我们即将陷入其中。

看,call()不明白的是,他不是镇上唯一可以强迫数字的人。毕竟这是JavaScript——强制无处不在。

call()拿走了我的号码,我不会停下来,直到我摘下他的小骗子的面具,让他暴露在整个堆栈中

但是怎么做呢?我需要一个计划。它看起来像一个数字,但我知道它不是,一定有办法证明这一点。就是这样!它看起来像一个数字,但它能像一个数字一样吗?

我告诉个我需要他变得更大5倍 - 他没有问为什么,我没有解释。然后我做了任何优秀的程序员都会做的事情:我乘以了。当然,他没有办法假装摆脱这一切。

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

该死的!不仅乘法很好wtf还在那里。该死的这家伙和他的土豆。

到底是怎么回事?我整件事都错了吗?5真的是一个数字吗?不,我一定错过了什么,我知道,我一定忘记了什么,一些如此简单和基本的东西,以至于我完全忽略了它。

这看起来不太好,我已经写了几个小时的答案,但我仍然没有接近我的观点。我无法保持这种状态,最终人们会停止阅读,我必须想一些事情,我必须快速思考。

等等,就是这样!5不是25,25是结果,25是完全不同的数字。当然,我怎么会忘记?数字是不可变的。当你乘以5*5时,没有任何东西会被分配给任何东西,你只是创建了一个新的数字25

这一定是这里发生的事情。不知何故,当我乘< code > 5 * 5 时,< code > 5 必须被强制转换成一个数,并且该数必须是用于乘法的数。打印到控制台的是乘法的结果,而不是< code>five本身的值。< code>five不会被赋值——所以它当然不会改变。

那幺我如何得到<code>五个

> five++
5

啊哈!我抓住他了!每个人都知道< code>5 1是< code>6,这是我需要的证据来证明< code > 5 不是一个数字!那是个骗子!一个不会数数的糟糕的骗子。我可以证明。以下是实数的行为方式:

> num = 5
5
> num++
5

等等?这里发生了什么事?唉,我太沉迷于破坏< code>five了,以至于忘记了post操作人员是如何工作的。当我在< code>five末尾使用< code> 时,我是说返回当前值,然后递增< code>five。打印到控制台的是操作发生之前的值。< code>num实际上是< code>6,我可以证明这一点:

>num
6

是时候看看到底是什么了:

>five
6

…这正是它应该是的5不错,但我更好。如果<code>五个

> five.wtf
undefined

啊哈!我是对的。我抓住他了!现在是一个数字——它不再是一个对象了。我知道这次乘法技巧不会保存它。看实际上是五=五1。与乘法不同,运算符为分配一个值。更具体地说,它为它分配了五1的结果,就像乘法返回一个新的不可变数一样。

我知道我抓住了他,只是为了确保他不会扭动身子离开。我还有一个测试。如果我是对的,5现在真的是一个数字,那幺这就行不通了:

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

这次他不会骗我的。我知道<代码>土豆 将打印到控制台,因为这是分配的输出。真正的问题是,wtf还会存在吗?

> five.wtf
undefined

正如我所怀疑的 - 什么都没有 - 因为数字不能被分配属性。我们了解到,在学院的第一年;)

谢谢你,内森。多亏了你提出这个问题的勇气,我终于可以把这一切抛在脑后,继续处理一个新案子。

就像这个关于函数<code>toValue()

隗驰
2023-03-14

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

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

第一个是原语,第二个是对象。实际上,两者的行为是一样的,只是在打印到控制台时看起来不同。一个重要的区别是,作为一个对象,< code>new Number(5)接受新属性,就像任何普通的< code>{}一样,而基本的< code>5不接受:

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

对于初始<code>dis。调用(5)部分,请查看“this”关键字如何工作?。假设<code>调用的值,并且该操作将数字强制为更复杂的<code>numberobject形式。*稍后<code>将其强制回原语形式,因为加法操作<code>会产生一个新的原语。

> 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++

< code> 产生一个新的原始< code>6值...

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

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

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

孟意致
2023-03-14

在这里。有趣的是,在堆栈溢出上看到这一点:)

在逐步执行该行为之前,重要的是要澄清一些事情:

> < li>

数字值和数字对象(< code>a = 3与< code>a =新数字(3))非常不同。一个是原语,另一个是对象。不能将属性分配给基本体,但可以分配给对象。

两者之间的胁迫是隐含的。

例如:

(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

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

好的,我们开始吧。

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

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

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

现在,我们将属性 five.wtf 设置为“土豆”,并将 5 作为对象,果然它接受简单赋值。

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

使用< code>five作为对象,我确保它仍然可以html" target="_blank">执行简单的算术运算。可以的。它的属性还坚持吗?是的。

> five++
5
> five.wtf
undefined

现在我们检查< code >五。后缀增量的技巧是,整个表达式将根据原始值进行计算,然后递增该值。看起来< code>five仍然是5,但实际上表达式计算为5,然后将< code>five设置为< code>6。

5不仅被设置为6,而且被强制返回一个数值,所有属性都丢失。由于原语不能保存属性,5。wtf未定义。

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

我再次尝试将属性< code>wtf重新分配给< code>five。返回值意味着它是固定的,但事实上不是,因为< code>five是一个数字值,而不是一个数字对象。表达式的计算结果为< code>'potato?',但是当我们检查时,我们发现它没有被赋值。

> five
6

自后缀增量以来,5 个一直是 6

 类似资料:
  • 下表(按对象名称排序)列出了 Microsoft Office 中已有对象添加的属性。对象属性CommandBarButton Mask Picture CommandBars DisableAskAQuestionDropdown DisableCustomizeFileDialog AllowMultiSelect ButtonName DialogType FilterIndex Filte

  • 打字擦除页面上说 如果类型参数是无界的,则用其边界或对象替换泛型类型中的所有类型参数。因此,生成的字节码只包含普通类、接口和方法。 但是,对于以下类别: javap-c Foo打印: 为什么类型参数没有替换为绑定(CharSequence),而是保留为E?

  • 在使用一个库的时候碰到了一个很奇怪的问题,有个class实例化生成的对象,假设为A 对A的属性进行修改 打印A发现,其中的a属性并没有变,但是直接打印A.a是改变了的,请问这种情况大概会是什么原因呢,是有什么知识盲区吗,目前知道a属性是不可删除的属性,但是一般对象设置configurable=false也不会出现这种情况,如果不允许修改的话应该也会报错。。 (PS:A只是为了表述简化的例子,并不是

  • 数据表格将总图层和子图层的数据进行了汇总,当前图层所有数据的属性信息都展示在数据表格内,可以在表格内增加、修改、删除属性字段。 数据表格主要由两部分组成,一部分是按钮组,一部分是表格内容,其中表格内容里,每个表头都有自己的菜单 菜单 点击表格表头字段右边“更多菜单”,打开菜单可以根据需求增加列在前方、增加列在后方、删除列、修改列、或者勾选“字段内容不可重复” 菜单-新增列 点击菜单选择“增加列在前

  • 问题内容: 我正在使用Firebase和angular进行测验。在测验的最后,我想使用以下代码将新属性保存到users对象: 它可以工作,但也可以覆盖用户对象的所有属性。因此,该对象曾经像名称,用户名,电子邮件,密码等一样保存,但是当我按下topscore时,它成为该对象的唯一属性。为什么? 问题答案: 你为什么在这里使用?仅在将其三向绑定到Angular视图时才有用。如果您使用的是常规JavaS