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('')}}?根据故障发生的位置,这可能在 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()}},通常),然后对结果进行{{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在生产环境中使用了一个修补程序,该修补程序只解决了高阶问题,他说这个修补程序解决了他们的问题。他没有受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
by

评论者:favila

bq. 我并不真的非常关心规范,只有它在野外很重要。如果这不会影响Safari 6.05,我们不在乎。

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

CLJS-847: x.toString()在Safari 6.0.5上失败。解决方案是 ''+x(仅在设计宏的情况下完成)。
CLJS-890: ''+x对于定义valueOf的对象不会给出预期的结果。期望是调用x.toString(),而不是xvalueOf().toString(). 解决方案是在str宏中使用数组连接而不是字符串连接,但它并没有解决CLJS-847的''+x解决方案。

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

0
by

评论者:favila

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

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

0
by

评论者:nbeloglazov

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

...