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
我就是从这个错误中发现这个错误的。

0

评论者:neatonk

感谢提供链接。我明白你的意思。

0

评论由:dnolen 开发

使用 {{String}} 的问题似乎是一个巨大的性能损失,打印时的性能下降见 http://jsperf.com/string-vs-tostring2/6

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

0

评论者:nbeloglazov

在字符串和数字上的 Append 操作性能较好,但在对象上的表现较差,所以它并不是一个明显的影响性能的问题。如果我在处理对象时使用 (str) 转换为字符串,那么实际上我在当前实现中会因为性能而受损。
无论如何,当前 str 的实现是不正确的,因为它不遵守 toString 方法。这正是 str 函数应该做的事情。我相信编译器应该首先保证正确性,然后再考虑性能。

0

评论由:dnolen 开发

抱歉再次回过头来考虑此事,我认为真正的问题是我们只需要回滚 CLJS-801。

0

评论由:dnolen 开发

已将 CLJS-801 回滚至 master 分支

0

评论由: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()}} 通常,但如果检测到我们会触发 CLJS-847。(可以在启动时进行特化。)
0
by

评论由:dnolen 开发

有没有任何证据表明 str 的更高使用实际上存在问题?

0
by

评论由:favila 开发

使用加法运算符的字符串连接使用未标记的 {{ToPrimitive}} 抽象调用(它将首先尝试 {{x.valueOf()}},然后是 {{x.toString()}},通常),然后对那个结果进行 {{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 在生产中使用了只解决 高阶 情况的补丁,他说这个补丁解决了他们的问题。他不受 str 宏 case 的影响,因为要么已经使用了 ''+x(已应用 CLJS-801)或使用了 {{[x].join(')}}(尚未在 Safari 6.0.5 中进行测试,但可能有效)。

因此,如果我们用 ''+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
by

评论由:favila 开发

我只是对规范不是很关心,只要它在实际中有意义。如果这不会影响Safari 6.05,我们就不用担心。

为了明确,这里有两个问题

CLJS-847: 在Safari 6.0.5上x.toString()会失败。解决方法是''+x(只在str宏情况下完成)。
CLJS-890: ''+x对象的期望结果不符合预期。期望调用x.toString()而不是x.valueOf().toString()。修正方法是使用str宏中的数组连接而不是字符串连接,但这并没有解决CLJS-847中的''+x解决方法。

更糟糕的是,看起来Safari上的toString()错误可能只在某些JIT级别才会触发!

0
by

评论由:favila 开发

解决方案是''+x(只在str宏情况下完成)。

我的意思是“解决方案是''+x(只在str 函数 情况下完成)。"

0
by

评论者:nbeloglazov

在同时,能否重新打开这个错误?如果我理解正确,修复应该会影响到https://github.com/clojure/clojurescript/commit/08b4b1585cf0ef739e903985ee4c6b7fc6c47642,但代码仍然在HEAD中。

...