请在 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
by

由:neatonk 评论

toString 和 valueOf 不一致是否有有效 用例?例如。

`(not= (.toString x) (js/String (.valueOf x))`

如果不一致,两个方法不一致是否“不正确”?

0
by

由:nbeloglazov 评论

这是一个这样的用例的例子:https://github.com/processing-js/processing-js/blob/master/src/Objects/Char.js
这就是我找到这个错误的方式。

0
by

由: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}}的返回值(或带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,则使用 {{String(x)}}。(可以在启动时进行特殊化。)
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 对 Object 调用) http://www.ecma-international.org/ecma-262/5.1/#sec-8.12.8

0
by

评论者:dnolen

我对规范本身并不真正关心,除非它在野外很重要。如果这不会影响 Safari 6.05,我们就不关心。

0
by

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

段首句. 我并不真的很关心这一规范,只有它在实际使用中有意义的情况下我才关心。如果这不会影响 Safari 6.05,我们就不在乎。

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

CLJS-847: 在 Safari 6.0.5 上,x.toString() 调用失败。解决办法是 ''+x(只在 str 宏情况下进行)。
CLJS-890: ''+x 对于定义了 valueOf 方法的对象没有预期的结果。预期的结果是调用 x.toString(),而不是 x.valueOf().toString()。解决办法是在 str 宏中使用数组连接代替字符串连接,但并不解决来自 CLJS-847 的 ''+x 是替代方案的漏洞。

更糟糕的是,看起来 Safari 上的 toString() 错误可能只在某些 JIT 级别下才会触发!

0
by

评论者:favila

段首句. 解决方案是 ''+x(只在 str 宏情况下进行)。

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

0
by

由:nbeloglazov 评论

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

...