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
by

评论者:dnolen

使用 String 会有这样的问题,看起来是打印时的性能大幅下降。详情见这里

除非提出一个聪明的解决方案,否则这似乎最好在用户代码中解决这个问题或绕过。

0
by

评论由:nbeloglazov添加

对于字符串和数字,append 的性能更好,但在处理对象时表现较差,因此不是明显的性能损失。如果我在对象上做很多操作,并使用 (str) 将它们转换为字符串,那么根据目前的实现,我的性能实际上会有所下降。
无论如何,目前的 str 实现是错误的,因为它不遵守 toString 方法。这正是 str 函数应该做的事情。我相信编译器首先应该是正确的,然后再考虑性能。

0
by

评论者:dnolen

抱歉,我回顾了一下,我认为问题是我们需要回滚 CLJS-801。

0
by

评论者:dnolen

已回滚 CLJS-801 到 master。

0
by

评论者:favila

CLJS-801 仅处理 str 。我们不是还会因为 CLJS-847 出现 str 函数 的问题吗?见这里(如果我们在那里使用 toString,Safari 6.0.5 会崩溃。也许我们需要 use {{[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

兼任. 有任何证据表明,高频率使用str实际上是有问题的吗?

打开 CLJS-847 的 Kevin Neaton 在生产环境中使用了一个补丁,该补丁仅解决高阶 case,他表示补丁解决了他们的问题。他对 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

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

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

...