请在2024年Clojure状态调查中分享您的想法!

欢迎!有关本站的工作方式,请参阅关于页面以获取更多信息。

0
ClojureScript

示例

(str #js {"toString" (fn [] "hello") "valueOf" (fn [] 42)}) ; => "42"

问题在于ClojureScript使用连接来将值转换为字符串,这对于覆盖了valueOf()方法的对象来说效果不佳。

JavaScript示例

`
var obj = {

toString: function() { return 'hello'; },
valueOf: function() { return 42; }

};
console.log(String(obj)); => 'hello'
console.log(obj.toString()); => 'hello'
console.log('' + obj); => '42'
`

可能的解决方案可能是使用String()函数。使用toString()不会按此问题中所述起作用:http://dev.clojure.org/jira/browse/CLJS-847

35 个答案

0

评论者:neatonk

toString和valueOf不匹配是否有有效用例?例如。

`(not= (.toString x) (js/String (.valueOf x))`

如果没有,两个方法不匹配是否“不正确”?

0

评论者:nbeloglazov

以下是一个此类用例的示例:https://github.com/processing-js/processing-js/blob/master/src/Objects/Char.js
这就是我发现这个bug的方式。

0
by

评论者:neatonk

感谢提供链接。我理解你的意思。

0
by

评论者:dnolen

使用 {{String}} 的问题似乎在于打印时会带来巨大的性能损失http://jsperf.com/string-vs-tostring2/6

除非提出一个绝妙的想法,否则似乎最好在用户代码中解决这个问题/规避它。

0
by

评论者:nbeloglazov

对于字符串和数字,append方法的性能更好,但对于对象则性能较差,因此并不是一个明显的性能损失。如果我在处理对象时大量使用(str)来将它们转换为字符串,那么根据当前实现,我实际上在性能上会受到损失。
无论如何,str的当前实现是不正确的,因为它不遵守toString方法。这正是str函数应该做的。我相信编译器应该首先正确,然后再考虑性能。

0
by

评论者:dnolen

抱歉重新审视这个问题,我认为真正的问题是我们需要回滚CLJS-801。

0
by

评论者:dnolen

在master中回滚了CLJS-801

0
by

评论者:favila

CLJS-801只处理str 。我们不还是在CLJS-847的影响下存在str 函数问题吗?https://github.com/clojure/clojurescript/commit/08b4b1585cf0ef739e903985ee4c6b7fc6c47642(即便如此,如果我们在那里使用toString,Safari 6.0.5会崩溃。或许我们需要{{[o].join('')}}?根据错误发生的位置,这可能在Safari 6.0.5中也是错误的。)

我们需要非常具体做的事情是,以某种方式获取对象上的(用ECMASCRIPT术语){{ToString}}抽象操作的返回值(或者具有String提示的底层{{ToPrimitive}}抽象操作)。使用加法运算符进行字符串连接

根据我的观察,可能的选项有

  • {{x.toString()}}:因为CLJS-847而不可取
  • {{[x].join('')}}:应该可以工作(并且对于null/undefined也能正确处理),但我认为我们应该在Safari 6.0.5上进行测试。此外,它非常慢。
  • {{String(x)}}
  • {{String.prototype.concat(x)}}
  • {{String.prototype.slice(x,0)}} {{String.prototype.substring(x,0)}} {{String.prototype.substr(x, 0)}}
  • {{x.toString()}}通常是,但如果检测到则使用{{String(x)}}(可以在启动时进行特殊化。)
0
by

评论者:dnolen

有没有证据表明str使用频率更高实际上是有问题的?

0
by

评论者:favila

使用加法运算符进行字符串连接会使用未提示的{{ToPrimitive}}抽象调用(通常会尝试{{x.valueOf()}}然后是{{x.toString()}}),然后对{{that}}的结果进行{{ToString}}转换,所以它不是选项,除非我们在合并原始值。

详情
ToString http://www.ecma-international.org/ecma-262/5.1/#sec-9.8
ToPrimitive http://www.ecma-international.org/ecma-262/5.1/#sec-9.1
* DefaultValue(由ToPrimitive对对象调用)http://www.ecma-international.org/ecma-262/5.1/#sec-8.12.8

0
by

评论者:dnolen

我并不真正关心规范,只有当它在野外很重要时才关心。如果这不会影响Safari 6.05,我们就不在乎。

0
by

评论者:favila

bq. 有没有证据表明str使用频率更高实际上是有问题的?

打开CLJS-847的Kevin Neaton在一个生产环境中使用了一个补丁,该补丁仅解决了高阶情况,他表示补丁已为他们修复了问题。由于它要么使用了''+x(已应用CLJS-801)要么使用了{{[x].join('')}}(尚未与Safari 6.0.5进行过测试,但可能工作),所以他不受str宏案例的影响。

所以如果我们使用 ""+x 与 str 宏存在问题,那么在应用 CLJS-847 后,使用 ""+x 与字符串函数也会存在问题。

我还没有拉取 master 分支,但这里有一个测试用例,我相信在 CLJS-847 补丁下会失败

(def tricky-obj #js {"toString" (fn [] "hello") "valueOf" (fn [] 42)}) (assert (= (apply str tricky-obj) "hello")) ;; 将得到 "42"

0

评论者:favila

bq. 我并不真正关心规范,只有在野外有关系时才关心。如果这不会影响 Safari 6.05,我们就没关系。

为了清楚起见,这里有两个问题

CLJS-847:x.toString() 在 Safari 6.0.5 上失败。解决方案是 ''+x(仅在 str 宏情况下执行)。
CLJS-890:''+x 对未定义valueOf的方法的对象没有给出预期结果。预期调用 x.toString(),而不是 x.valueOf().toString(). 解决方案是在 str 宏中使用数组连接代替字符串连接,但它没有解决 CLJS-847 中的 ''+x 解决方案。

更糟的是,看起来 Safari 上的 toString() 错误可能仅在特定的 JIT 级别触发!

0

评论者:favila

bq. 解决方案是 ''+x(仅在 str 宏情况下执行)。

我的意思是 "解决方案是 ''+x(仅在 str 函数 情况下执行)。"

0

评论者:nbeloglazov

这个错误现在可以重新打开吗?如果我理解正确,修复应该影响 https://github.com/clojure/clojurescript/commit/08b4b1585cf0ef739e903985ee4c6b7fc6c47642,但这段代码仍然存在于 HEAD。

...