Clojure 2024 状态调查! 中分享您的想法。

欢迎!请参阅 关于 页面了解更多有关如何使用本站的信息。

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
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会崩溃。也许我们需要[用这种方式]?根据错误的地点,这可能在Safari 6.0.5中也是错误的。

我们需要非常具体地获取对象(在 ECMASCRIPT 术语中)的 {{ToString}} 抽象运算的返回值(或在具有字符串提示的 {{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 将触发 {{String(x)}}。(可以在启动时专门化。)
0

评论者:dnolen

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

0

评论者: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

评论者:dnolen

我并不真的很关心规范,只是如果它在野外很重要,那么我们不关心。如果这不会影响 Safari 6.05,那么我们不关心。

0

评论者:favila

“是否有任何证据表明更高频率的使用 str 实际上存在问题?”

Kevin Neaton,他开启了 CLJS-847,在生产中使用了仅处理高阶情况的补丁,他说此补丁为他们解决了问题。他不受 str 宏情况的 str,因为它要么已经使用 ''+x(应用了 CLJS-801)或者使用 {{[x].join('')}}(尚未用 Safari 6.0.5 进行测试,但可能可行)。

如果我们使用 ' '+x 与 str 宏时出现任何问题,那么在 CLJS-847 设置 apply 后,使用字符串函数的 ' '+x 也将存在问题。

我尚未拉取 master,但是这里有一个测试用例,我敢打赌应用 CLJS-847 补丁后会失败。

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

0
by

评论者: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
by

评论者:favila

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

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

0
by

评论由:nbeloglazov 发布

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

...