Firefox中Greasemonkey脚本中的JavaScript类型强制和字符串连接问题

Yi *_*ang 12 javascript string firefox greasemonkey type-conversion

我正在创建一个GreaseMonkey脚本来改进Stack Overflow使用的10k工具的用户界面.我遇到了一个不可复制的,坦率的奇怪的问题,使我和其他人在SO聊天的JavaScript室里感到困惑.我们还没有经过查找原因,多次长时间的 调试 会话.

有问题的脚本可以在这里找到.来源 - 安装


问题发生在第85行,即"vodoo"评论之后的行:

return (t + ' (' + +(+f.offensive + +f.spam) + ')');
Run Code Online (Sandbox Code Playgroud)

它可能看起来有点奇怪,但是+两个变量和内部括号前面是类型强制,内部中间+是用于加法,而其他变量用于连接.

没什么特别的,但细心的读者可能会注意到内部括号上的类型强制是不必要的,因为两者都已被强制转换为数字,并且类型强制结果无论如何都被连接成一个字符串是没用的.不是这样!删除+脚本中断,导致f.offensivef.spam连接而不是一起添加.

进一步添加console.log只会让事情变得更加混乱:

console.log(f.offensive + f.spam); // 50
console.log('' + (+f.offensive + +f.spam)); // 5, but returning this yields 50 somehow
console.log('' + (+f.offensive + +f.spam) + ''); // 50
Run Code Online (Sandbox Code Playgroud)

资料来源:http://chat.stackoverflow.com/transcript/message/203261#203261


问题是这是不可复制的 - 运行脚本如

console.log('a' + (+'3' + +'1') + 'b');
Run Code Online (Sandbox Code Playgroud)

在Firebug控制台中产生正确的结果,就像这样

(function(){
    return 'a' + (+'3' + +'1') + 'b';
})();
Run Code Online (Sandbox Code Playgroud)

即使拔出大块代码并在控制台中运行它们也不会重现这个错误:

$('.post-menu a[id^=flag-post-]').each(function(){
    var f = {offensive: '4', spam: '1'};

    if(f){
        $(this).text(function(i, t){
            // Vodoo - please do not remove the '+' in front of the inner bracket
            return (t + ' (' + +(+f.offensive + +f.spam) + ')');
        });
    }
});
Run Code Online (Sandbox Code Playgroud)

聊天室里的Tim Stone 为那些低于10k的人提供了复制指导.


此错误仅出现在Firefox中 - Chrome似乎没有出现此问题,这让我相信这可能是Firefox的JavaScript引擎或Greasemonkey加载项的问题.我对吗?

如果您想要更多细节和/或想要讨论这个问题,我可以在JavaScript会议室找到.

Tim*_*one 7

作为用户脚本过程的一部分,将<script>标记注入到页面中,并通过调用toString()您定义的函数来检索代码.通常情况下这很好,但似乎Firefox 3.6.13使用的javascript引擎中存在一个错误,该错误重定位表达式中的括号,导致在toString()处理-ified函数时以非常不同的方式对其进行求值.

为了说明这个问题,我们可以在Firebug中运行以下代码:

function f() { var a = '', b = '1', c = '2'; return a + '(' + (+b + +c) + ')'; };
f.toString();
Run Code Online (Sandbox Code Playgroud)

这给了我们这个输出:

function f() {
    var a = "", b = "1", c = "2";
    return a + ("(" + + b + + c + ")");
}
Run Code Online (Sandbox Code Playgroud)

您会注意到返回表达式已被修改.括号已经重新定位到以前在它们之外的字符串,导致变量b并被c强制转换为字符串并连接.这给出了意想不到的结果,因为预期的添加永远不会发生.不幸的是,这种行为即使使用目前Number()parseInt()强迫bc.

有几个小的修改可以改变这一点,但最清楚的只是事先将添加的结果保存到变量中:

$(this).text(function(i, t){
    var c = +f.offensive + +f.spam;
    return (t + ' (' + c + ')');
});
Run Code Online (Sandbox Code Playgroud)

值得庆幸的是,Firefox 4 beta中似乎没有出现这个问题,所以希望这个问题在未来得到解决.此外,Matthew Flaschen已经慷慨地提出提交了一份错误报告(标记为559438的副本),以便开发人员在任何一种情况下都能了解这个问题.

  • 并且非常感谢JavaScript会议室中的每个人为他们的贡献http://chat.stackoverflow.com/rooms/17/conversation/the-solution (4认同)