Проблема с приведением типов и конкатенацией строк в JavaScript в скрипте Greasemonkey в Firefox - PullRequest
12 голосов
/ 17 декабря 2010

Я создаю скрипт GreaseMonkey для улучшения пользовательского интерфейса инструментов 10k, которые использует Stack Overflow.Я столкнулся с невоспроизводимой и откровенно странной проблемой, которая смутила меня и других в комнате JavaScript в SO Chat.Мы еще не нашли причину после нескольких длительных отладки сессий .

Проблемный скрипт можно найти здесь . Источник - Установить


Проблема возникает в строке 85, строка после комментария 'vodoo':

return (t + ' (' + +(+f.offensive + +f.spam) + ')');

Этоможет показаться немного странным, но + перед двумя переменными и внутренняя скобка - для приведения типов, внутренняя середина + - для сложения, а остальные - для объединения.

Ничего особенного, но наблюдательный читатель может заметить, что приведение типов во внутренней скобке не нужно, поскольку оба типа уже приводятся к числам, а результат принудительного ввода типов бесполезен, когда они в любом случае объединяются в строку.Не так!Удаление + нарушает работу сценария, в результате чего f.offensive и f.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

Источник: http://chat.stackoverflow.com/transcript/message/203261#203261


Проблема в том, что это невоспроизводимо- запуск сценариев, таких как

console.log('a' + (+'3' + +'1') + 'b');

в консоли Firebug, дает правильный результат, как и

(function(){
    return 'a' + (+'3' + +'1') + 'b';
})();

Даже извлечение больших кусков кода и запуск их в консоли не приводит к воспроизведениюэта ошибка:

$('.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) + ')');
        });
    }
});

Тим Стоун в чате имеет инструкцию по воспроизведению для тех, кто ниже 10k.


Эта ошибка появляется только в Firefox - похоже, что в Chrome эта проблема не возникает, что позволяет предположить, что это может быть проблема либо с движком JavaScript Firefox, либо с надстройкой Greasemonkey.Я прав?

Меня можно найти в комнате JavaScript , если вы хотите больше подробностей и / или хотите обсудить это.

1 Ответ

7 голосов
/ 17 декабря 2010

Как часть процесса пользовательского сценария, на страницу вводится тег <script> с кодом, полученным путем вызова toString() для определенной вами функции.Обычно это было бы хорошо, но похоже, что в движке javascript, используемом Firefox 3.6.13, есть ошибка, которая перемещает скобки в выражении, вызывая его оценку совсем по-другому, когда toString() -тифицированная функцияобработано.

Чтобы проиллюстрировать эту проблему, мы можем запустить следующий код в Firebug:

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

Это дает нам такой вывод:

function f() {
    var a = "", b = "1", c = "2";
    return a + ("(" + + b + + c + ")");
}

Вы заметитечто возвращаемое выражение было изменено.Скобки были перемещены за пределы строк, которые ранее находились за их пределами, в результате чего переменные b и c были приведены к строкам и объединены.Это дает неожиданный результат, так как ожидаемое добавление никогда не происходит.К сожалению, такое поведение присутствует даже при использовании Number() или parseInt() для приведения b и c.

Существует несколько небольших модификаций, которые изменяют это, но самым простым является сохранение результата.о добавлении к переменной заранее:

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

К счастью, эта проблема, по-видимому, не возникает в бета-версии Firefox 4, так что, надеюсь, эта проблема будет решена в будущем.Кроме того, Matthew Flaschen любезно продвинулся вперед и подал отчет об ошибке (отмечен как дубликат 559438 ), так что разработчики были осведомлены об этой проблеме в любом случае.

...