最近的一条推文包含了这段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
特别是,我不清楚:
爪哇脚本世界中有胁迫 - 侦探故事
内森,你不知道你发现了什么。
我已经调查了几个星期了。这一切都始于去年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()
有两种不同的方法来表示数字:
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。
在这里。有趣的是,在堆栈溢出上看到这一点:)
在逐步执行该行为之前,重要的是要澄清一些事情:
> < 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