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

欢迎!请查看关于页面以了解更多关于此的信息。

0投票
ClojureScript

示例

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

问题在于ClojureScript使用拼接将值转换为字符串,而这与具有valueOf()方法被覆盖的对象不兼容。

js中的示例

`
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 提出

在 master 中回滚 CLJS-801

0投票

评论区由:favila 提供

CLJS-801仅处理str 。我们是否仍然会因为CLJS-847而遇到str 函数问题?https://github.com/clojure/clojurescript/commit/08b4b1585cf0ef739e903985ee4c6b7fc6c47642(即使我们使用toString,Safari 6.0.5也会崩溃。也许我们需要{{[o].join('')}}?根据bug的位置,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投票

评论区由:dnolen 提出

是否有任何证据表明高频率使用str确实有问题?

0投票

评论区由: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投票

评论区由:dnolen 提出

我对规范本身并不是很关心,只有当它在大野中使用时才关心。如果这不会影响Safari 6.05,我们就不关心。

0投票

评论区由:favila 提供

bq.是否有任何证据表明高频率使用str确实有问题?

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

因此,如果我们使用 str 宏的 ''+x 存在问题,那么在 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 提供

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 function 情况下进行)。”

0投票
by

评论者:nbeloglazov

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

...