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

在字符串和数字上,追加操作表现更好,但在对象上表现较差,因此这并非一个明显的性能影响。如果我大量使用对象并且使用(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('')}}?根据错误发生的位置,这可能在 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()}} 通常,但 {{String(x)}} 如果我们检测到它会触发 CLJS-847。(可以在启动时特别化。)
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

bq. 是否有任何证据表明-str 使用频率越高实际上是有问题的?

Kevin Neaton,他打开了 CLJS-847,在生产的补丁中只解决了高阶情况,他说补丁解决了他们的问题。他对-str 宏的情况没有影响,因为要么已经使用了 ''+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 投票

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

...