ЙажаСценарий / Говнокод #16141 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
(function(G, D) {
    "use strict";
    var $ = G.jQuery,
        listener;

    function addListener(elem, fn) {
        function handler(event) {
            event = event || G.event;
            var dx = event.DeltaX || event.wheelDeltaX || event.detail || 0,
                dy = event.DeltaY || event.wheelDeltaY || event.detail || 0;
            event.dx = dx === 0 ? 0 : dx / Math.abs(dx);
            event.dy = dy === 0 ? 0 : dy / Math.abs(dy);
            fn(event);
        }

        if (elem.addEventListener) {
            if (D.hasOwnProperty('onwheel')) { //Modern browsers
                listener = "wheel";
            } else if (D.hasOwnProperty('onmousewheel')) { //Old browsers
                listener = "mousewheel";
            } else { //FF<17
                listener = "MozMousePixelScroll";
            }
            elem.addEventListener(listener, handler, false);
        } else { //IE<9
            elem.attachEvent("onmousewheel", handler);
            listener = "onmousewheel";
        }
    }

    function removeListener(elem) {
        if (elem.removeEventListener) {
            elem.removeEventListener(listener);
        } else {
            elem.detachEvent(listener);
        }
    }

    $.fn.mousewheel = function(fn) {
        return this.each(function() {
            addListener(this, fn);
        });
    };
    $.fn.unmousewheel = function(fn) {
        return this.each(function() {
            removeListener(this, fn, false);
        });
    };
}(this, document));

Написал плагин для jQuery, который цепляет на элементы обработчик события вращения колесика мыши. Что скажете? Как бы вы написали функцию unmousewheel()?

Запостил: dunmaksim dunmaksim, (Updated )

Комментарии (103) RSS

  • 1. глобальную для плагина переменную listener можно хакнуть
    2. removeEventListener удаляет undefined
    $('body').mousewheel(f); // listener == "wheel"
    $(42).mousewheel(g); // listener == "onmousewheel"
    $('body').unmousewheel(f); // вызовется body.removeEventListener("onmousewheel", undefined)
    Ответить
      • >Интересен новый вариант?
        Только если там говна еще больше
        Ответить
        • Так и есть.
          1. Значение listener всё так же одно на всех, его всё ещё можно изменить.
          2. Настоятельно рекомендую автору открыть https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.removeEventListener и кормить removeEventListener нужными ему аргументами (да и detachEvent тоже)

          В новой версии добавлено:
          1. typeof x === "array". В текущей версии JS typeof [] === "object". [] instanceof Array может при каких-то случаях глюкнуть, но в вашем jQuery есть isArray http://api.jquery.com/jquery.isarray/
          2. for (i in this.wheelEvents) - не надо так.
          Array.prototype.trololo = 42;
          for(var i in []) alert(i); // выполнится alert('trololo');

          3. Кажется (по сигнатуре), что removeListener удаляет только одну функцию, но нет, это обман, он удаляет все сразу.
          4. А в строке 58 пропущено "elem." Из-за того, что typeof elem.wheelEvents никогда не примет значение "array", строка 58 никогда не вызовется и "use strict" не спасёт.
          5. elem.wheelEvents = []; - нехорошо как-то дополнять объекты
          (хотя, в jQuery, судя по исходникам (src/data/Data.js, src/event.js), дополняют объект полем с уникальным для каждого экземпляра Data именем (jQuery.expando + Math.random()) и уникальным для каждого объекта значением (Data.uid++), а данные хранят в экземпляре Data). Раз уж так вышло, что в объект что-то добавлено, можно и строку listener в сам объект складывать.
          Но раз в jQuery для привязывания событий используют Data, надо бы и автору посмотреть http://api.jquery.com/jquery.data/.
          Ответить
          • Учёл практически все замечания. Новая версия должна быть гораздо интересней. На выходных, если будет время, допилю.
            Ответить
            • > $.data(elem, "wheelHandlers", []);
              Я не знаю традиций пользователей jQuery, потому меня имена немного смущают: вдруг их кто-нибудь займёт. А может, так и надо.

              > $.data(elem, "wheelListener", undefined);
              Ха-ха, undefined не пройдёт.
              http://james.padolsey.com/jquery/#v=1.10.2&fn=_internalData:
              if (data !== undefined) {
                  thisCache[jQuery.camelCase(name)] = data;
              }
              Ответить
              • Точно, нашёл jQuery.removeData(), который решает проблему с undefined.
                Хранить что-либо в свойствах объекта я тоже считаю неправильным, однако же, нет никакого другого способа в данном случае корректно управлять списком обработчиков.
                Ответить
            • Рядом же лежит оригинальный mousewheel.js, из которого и получают этот минифицированный mousewheel.min.js. Что не так?
              Ответить
              • меня эта херня бесит и всегда бесила. создавали тогда полноценное промежуточное представление.

                в общем это некрасиво, а я эстет
                Ответить
                • Братюнь, там лежат mousewheel.js и mousewheel.min.js, первый файл - полный исходный код, второй - сжатый. Что тебе не понятно?
                  Ответить
                • > в общем это некрасиво, а я эстет
                  Я с тобой согласен. И, наверное, как минимум половина других разрабов тоже. Нормальный байткод как в жабе или шарпе был бы удобней и шустрее.

                  Но к сожалению минифицированный жабоскрипт это единственное промежуточное представление, которое работает в браузерах. И все новые языки типа кофейного свитка или печатного свитка компилятся именно в него. И новое внедрить будет очень сложно, а на практике - почти нереально. Так что считай это просто байткодом, и не читай 🙂
                  Ответить
                  • читай не читай - для меня это так и останется однострочным блядством. Грустно все это. Пойду поредуцирую
                    Ответить
                    • > однострочным блядством
                      > Грустно все это.
                      Если минифицированный вариант будет длиннее где-то 500 символов, в большинстве случаев будет уже больше одной строчки. Не грусти, товарищ!
                      Ответить
                      • >>будет уже больше одной строчки
                        Спасибо, отпустило
                        Ответить
                    • > для меня это так и останется однострочным блядством.
                      Бинарники ты тоже открываешь в редакторе, а потом обзываешь нечитаемым блядством? Просто считай эти файлы бинарниками. Увидел файл .min.js - пройди мимо, или найди его оригинал на сайте разрабов.

                      P.S. Отладчик огненной лисы, к слову, умеет превращать этот минифицированный код в читаемый и многострочный. Правда названия переменных он уже не восстановит, и они так и останутся a, b, c и т.п.
                      Ответить
                      • Ну бинарники и не притендуют. Хотя я, конечно, могу и так
                        Ответить
                      • > Бинарники ты тоже открываешь в редакторе, а потом обзываешь нечитаемым блядством?
                        А вдруг он олдфаг и поклонник PDP-11. А тут уже 2014й на дворе и гигабайты нечитаемого блядства.

                        > Отладчик огненной лисы
                        (для справки) И Webkit Devtools умеет, кнопка {}
                        Ответить
                        • Все нормальные ide для скобкоблядских языков умеют в автоформат.
                          Ответить
                      • Любопытсва ради восстановил как-то js-код сжатый через расширение WebEssentials для VS - оказывается он не просто сжимает, но еще модифицирует исходный код. Например если перед return в функции есть выражение, он его ставит после return и как бы делает lazy evaluation. А все true и false превращает в !0 и !1
                        Ответить
                        • Ага, а для Closure Compiler ещё многостраничный ман надо бы прочитать перед тем, как начать сжимать с агрессивными настройками.
                          function f(){ return 3; }
                          window["f"] = f; // иначе f сгинет, если никто его не использует (или его имя будет утрачено)
                          Ответить
                • > создавали тогда полноценное промежуточное представление
                  mousewheel.min.map в помощь
                  Ответить
          • dx === 0 ? 0 : dx / Math.abs(dx);

            а функции знака нет?

            или компаратора -1,0,1 ?
            типа

            dx = comp(dx,0);
            Ответить
            • Зачем ты пишешь вообще, если не разбираешься в языке, о котором идёт речь?
              Ответить
              • я спрашиваю, мне интересно. а ты какой то сильно умный
                Ответить
              • Так он вопросы задает. А вообще на гк принято критиковать то, что не знаешь.
                Ответить
                • Вспомнилась старая шутка:
                  американский форум: задал вопрос - получил ответ
                  немецкий форум: задал вопрос - дали ссылку, где можно получить ответ
                  русский форум: задал вопрос - объяснили, что твоя мать шлюха и ты сам не лучше
                  Ответить
            • > А функции знака нет?
              Есть, Math.sign(dx). Но вот за что я и обожаю js:
              Chrome 32
              Firefox (Gecko) 25
              Internet Explorer Not supported
              Opera Not supported
              Safari Not supported


              P.S. Но деление для определения знака это все же пиздец. Достойно отдельного ГК.
              Ответить
              • Вот так будет и наглядней и шустрее: x < 0 ? -1 : x > 0 ? 1 : 0
                Ответить
                  • со мной не согласен, а с ним согласен. Ах ты двуличная мразь.
                    Ответить
                • не быстрее и не нагляднее.
                  не быстрее, т.к. лучше проводить сравнение: x==0?0:x>0?1:-1
                  не нагляднее, т.к. целых два вложенных тернарника и без скобок
                  Ответить
                  • > не быстрее, т.к. лучше проводить сравнение: x==0?0:x>0?1:-1
                    Зависит от распределения: если нули встречаются чаще всех остальных чисел, ну ок, сначала лучше проверить на 0. Если положительные - то в моем варианте стоит поменять местами ветки. Но один хрен второй тернарник всяко быстрее деления...

                    > два вложенных тернарника и без скобок
                    Пыхопроблемы? 🙂 Во всех остальных сиподобных языках цепочки тернарников нормально работают и даже неплохо читаются: если x отрицательный, то -1; если х положительный, то 1; иначе 0.
                    Ответить
                    • Вопрос::Оффтоп

                      В хаски вообще можно описать унарный оператор? Или только функцию?

                      class Square a where 
                      	(#) :: a->a
                      	
                      instance Square Integer where
                      	(#) a = a*a


                      Компилиться, но не дает применить. Для бинарных операторов канает, sqr вместо # тоже.

                      Сорри за оффтоп, ничего вразумительного не могу найти, видимо слепой
                      Ответить
                    • >> не быстрее, т.к. лучше проводить сравнение: x==0?0:x>0?1:-1
                      >Во всех остальных сиподобных языках цепочки тернарников нормально работают и даже неплохо читаются: если x отрицательный, то -1; если х положительный, то 1; иначе 0.
                      Несишкобляственно. Быстрее без ветвлений.

                      (x>0)-(x<0)
                      Это смайл если что.
                      Ответить
                        • false - false == false
                          false - true == false
                          true - false == true
                          true - true == false
                          false + false == false
                          false + true == true
                          true + false == true
                          true + true == true
                          false * false == false
                          false * true == false
                          true * false == false
                          true * true == true
                          false / false == UB
                          false / true == false
                          true / false == UB
                          true / true == true
                          
                          var = true
                          ++ var 
                          var == ID (implementation defined)
                          
                          var = true
                          -- var 
                          var == false
                          
                          var = false
                          -- var 
                          var == ID (implementation defined)
                          
                          var = false
                          ++ var 
                          var == true


                          Всё верно?
                          Ответить
                          • > Всё верно?
                            В каком языке? Если в жс - то почти всё неверно. Для крестов - тоже далеко не всё.
                            Ответить
                            • Пусть будут кресты. Исполняем только левую часть. Какие замечания и исправления?
                              Ответить
                              • > Пусть будут кресты. Исполняем только левую часть. Какие замечания и исправления?
                                b1 `op` b2 вернет число, а не bool.
                                5.7:1 The additive operators + and - group left-to-right. The usual arithmetic conversions are performed for operands of arithmetic or enumeration type.
                                5:9 Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield result types in a similar way. The purpose is to yield a common type, which is also the type of the result. This pattern is called the usual arithmetic conversions, which are defined as follows:
                                <...>
                                — Otherwise, the integral promotions (4.5) shall be performed on both operands [54].
                                <...>
                                54) As a consequence, operands of type bool, wchar_t, or an enumerated type are converted to some integral type.

                                ++b и b++ всегда помещают true в b (разбирали недавно, )
                                5.2.6:1 After the result is noted, the value of the object is modified by adding 1 to it, unless the object is of type bool, in which case it is set to true. [Note: this use is deprecated, see annex D. ]

                                --b и b++ не компилится вообще (разбирали в том же треде)
                                5.2.6:2 The operand of postfix -- is decremented analogously to the postfix ++ operator, except that the operand shall not be of type bool.
                                Ответить
                          • Ну и заодно - что в этом коде обозначает ==?
                            1) Это реальный оператор языка, и мы исполняем каждую строчку твоего кода дословно, после чего она должна вернуть истину. Тогда утверждение true + true == true ложно, равно как и true + true == false.
                            2) Либо == тут наивно-декоративное и мы исполняем только левую часть. И если эту левую часть подставить в условие, то получим тот же самый эффект, что и если подставить туда правую часть: if (true + true) и if (true) сработают одинаково, а if (true + true) и if (false) - нет.

                            Т.е. true + true является истинным, но в то же время не == true...
                            Ответить
                        • >>Вот так будет и наглядней и шустрее: x < 0 ? -1 : x > 0 ? 1 : 0
                          >> Но деление для определения знака это все же пиздец. Достойно отдельного ГК.
                          А вот я вступлюсь за код вышеобосранного кегдана. А там ведь результатов возврата 4, а не 3.

                          >Красиво, въебал плюс.
                          Его код был пока что единственным который выдает правильные результаты на всем множестве входных параметров (проверял в других языках - логика та же)
                          Сделал еще неочевиднее свой вариант.
                          (x==x) ? (x>0)-(x<0) : x
                          http://ideone.com/I67qbb
                          Ответить
                          • Да, про NaN то я и забыл. Кстати, в ecma6 вообще 5 разных значений:

                            Данная функция имеет 5 видов возвращаемых значений: 1, -1, 0, 0 и NaN, которые означают "положительное число", "отрицательное число", "положительный ноль", "отрицательный ноль" и NaN соответственно.
                            Ответить
                            • > "положительный ноль", "отрицательный ноль"
                              А какой толк от них в жс? Чтобы делать 1/Math.abs(0) вместо 1/0?
                              Ответить
                            • Ох, вот нечем придуркам занятся. В языке нет самых примитивных минимально необходимых инструментов, символьного типа, целочисленного типа, потоков (и тех и других), коллекций, синтаксических инструментов и еще кучи всего, а они решили добавить отрицательный ноль. Чтобы очередная обезьяна вместо того, чтобы заниматься полезной работой типа изучения структур данных и алгоритмов занималась изучением изьебистых и совершенно бесполезных особенностей языка.
                              Ответить
                              • Ах ты ж ёбаный нахуй, оно еще и [42] кастует в 42!

                                Нет, на js без юнит-тестов писать вообще невозможно.

                                Вот вроде бы все тесты проходит: http://ideone.com/MGZQK4
                                Ответить
                                • http://ideone.com/mB0iWo
                                  Ещё есть {valueOf: function(){ return 42;}}, {toString: function(){ return '42';}}, подобные объекты весело ломают код Кегдана в нуле ("=== помогает", говорили они).
                                  Ответить
                                • >typeof(x) != 'number' || isNaN(x) ? NaN : (x>0)-(0>x))
                                  Блин слишком очевидно. Бульдозерный стиль. Сразу раскрывает карты NaN. Я хотел:
                                  а) обойтись без встроенных функций
                                  б) использовать только свойства чисел
                                  в) чтоб код был коротким, но не очень понятным

                                  Вот более короткий вариант:
                                  !x ? x : (x>0)-(0>x)

                                  А есть спека как sign должен себя вести в жс?
                                  Ответить
                                • >>Вот вроде бы все тесты проходит
                                  >А есть спека как sign должен себя вести в жс?
                                  Чего я спрашиваю. Там не всё так просто. Проверяю в фф
                                  Math.sign(null)==0
                                  Math.sign(false)==0
                                  Math.sign(true)==1

                                  А fatality выдаёт NaN.
                                  Не вижу смысла задрачивать то что не является числом.
                                  Ответить
                              • >У Кегдана с +-Infinity жопа.
                                А кстати да. И у another борманда тоже (хотя идея интересная).

                                Я-то только свои на бесконечностях проверял.
                                Ну оба tangled - мои. Всё отличие "tangled code:" от "3.14159265 code:", это отрицание и перестановка местами.
                                Ответить
                            • В моем коде нет деления. Я тупо код не писал.

                              Я может и дурак, но не настолько, чтобы знак делением искать
                              Ответить
                              • >В моем коде нет деления. Я тупо код не писал.
                                Ну да, я уже заметил что код пришёл из оп-поста и как подсказал 1024-- он неправилен на бесконечностях.

                                >Я может и дурак, но не настолько, чтобы знак делением искать
                                А как его искать-то? Что может быть лучше и короче:
                                ((x>0)-(x<0)) / (+x==+x))
                                Ответить
                                • Ну это уже некоторые особенности анальной окупации в JS.
                                  Ответить
                                  • >Зато у Борманда быстрее.
                                    Только неправильно
                                    Math.sign(true)
                                    Math.sign(false)
                                    Math.sign(null)
                                    Ответить
                                      • На числах в фф оно всех обгоняет 🙂
                                        А в хроме и опере ВНЕЗАПНО изначальное деление быстрее всех.
                                        Ответить
                                      • http://jsperf.com/gksign
                                        Сделал тестирование чисто на числах, ибо по всякой херне типа функций считать знак и при этом хотеть скорости будет только безумец.
                                        Да и насторожило как туго работает родной Math.sign - может на строки и функции он не заточен?
                                        Результаты удивляют - Math.sign - хуже всех. Даже деление его обошло.
                                        И что удивительно fatality тоже слабовато.

                                        PS закешил длину массива и сделал прединкремент http://jsperf.com/gc-signum/4
                                        Особо ничего не поменялось.
                                        Ответить
                                      • Ternary strikes back!
                                        http://ideone.com/fTlmN7
                                        http://jsperf.com/gksign/2

                                        ?: реабилитирован - с минимальным фиксом даёт верный результат и эпично побеждает во всех трёх браузерах. Только фф додумался так же быстро выполнить моё странное байтоебство.
                                        Простой код и здравый смысл восторжествовали над "умными" хаками, написанными ради потехи.
                                        Ответить
                                        • Осталось только написать статью в стиле Царя.
                                          А сегодня мы будем тестить скорость работы сигнума на моём штеуде. Нечисла - питушня потому НаН, нулл и массивы оставим заедушным питушкам. Нормальные посоны используют тернарник, деление соснуло. Тернарник дал 1MOps. Питушиный Math.sign писали за еду, цари используют тернарники.
                                          Ответить
                                          • Не-не-не. Царь как раз нормальное решение - тернарники бы заговнил, а заодно и оперу, с хромом. Главное чтоб быстро, пусть в одном браузере и криво, но очень быстро.
                                            Хак (x>0)-(x<0) ему бы понравился - работает быстро в фф, на всех числах, но не всех входных значениях.
                                            В сленг сумасшедших я не умею, потому косплея не будет.
                                            PS> А Math.sign то действительно петушиный и абсолютно бесполезные - работает в полутора браузерах и адски медленно.
                                            Ответить
                                        • нет никаких ==== и =====. == - не строгое равенство, === - строгое

                                          типа
                                          3 =='3' - true
                                          3 === '3' - false
                                          Ответить
                            • Охохо. Трёмя крестами довёл практически до идеала:
                              Может креста должно быть джва?
                              x==+x ? (x>0)-(x<0) : +x

                              А главное: коротко, никаких функций, и сходу нихера непонятно как оно работает! Но работает правильно.
                              Ответить
                              • Гениально. Второй раз уже удивляете в этом треде.
                                Ответить
                                  • Гениально, но нужен ещё один крест, если поддерживать не только числа.
                                    +null==null -> false
                                    +null==+null -> true
                                    А в предыдущем примере - нет, т.к. null пойдёт по ветке сравнения с нулём, где правильно приведётся к нулю.
                                    Ответить
                            • Читаю этот тред и думаю: 49 строк кода, а проблем на целую книгу.
                              Ответить
                              • А ещё версии языка, реализации, оптимизации, кэш, процессоры, вентили, электроны, нуклоны, кварки, преоны...
                                Ответить
  • За эти два дня немного подновил исходный код на GitHub, советую посмотреть. Исправлена ошибка в новом IE (>8), а также теперь старые обработчики очищаются перед тем, как цеплять новые. Если у кого-нибудь есть возможность, пожалуйста, посмотрите, будет ли работать этот плагин в старых ослах.
    Ответить
    • 1. Всё же, detachEvent просит 2 аргумента, покормите его.
      Я сейчас в IE 11 переключился в режим IE 7, попробовал использовать detachEvent с одним аргументом - не удаляет.

      2. delete (handlers[i]); скорее всего делает не то, что Вы ожидаете, скорее всего не нужно.

      3. По поводу
      if (!elem.hasOwnProperty("wheelEvents")) {
          $.data(elem, HANDLERS, []);
      }

      Во-первых, "wheelEvents" более нигде не используется, во-вторых:
      3.1. $.data работает с местным хранилищем jQuery, хранятся любые объекты
      3.2. $.attr - с атрибутами объекта (DOM), аналогично встроеным elem.setAttribute, elem.getAttribute, хранятся строки
      3.3. elem.что-то - свойства объекта, иногда синхронизируются с атрибутами, но не эквивалентны
      Если Вы хотели написать if (!elem.hasOwnProperty(HANDLERS)), ничего не выйдет, в elem нет его (см. п.п. 3.1, 3.3). Тут надо либо смотреть результат $.data, либо найти в jQuery соответствующую функцию.
      4. Удаление старых обработчиков в addListeners - всё же странная фича.
      Ответить
      • Спасибо за ценные замечания. Попробовал сделать вот что:
        1. Никаких нативных JS-функций, привязанных к конкретному браузеру. Вместо этого с помощью jQuery(elem).on(); цепляется обработчик handler.
        2. Соответственно, удаление обработчика с помощью jQuery(elem).off();.
        3. Свойство handlers для объекта DOM удаляется целиком с помощью delete(). Будем надеяться, что браузер сможет правильно обработать эту ситуацию.
        Ответить
      • Прошу прощения за оффтоп: можете посоветовать хороший русскоязычный ресурс для обсуждения данного проекта? Место, где собираются профессионалы, которые могут дать дельный совет, указать на ошибки и т.д. - вот что я ищу. Хабр прошу не предлагать.
        Ответить
        • Вот это не знаю... говнокод.ру?
          Я человек скромный, никого ни о чём не спрашивал 🙂 Читал javascript.ru: учебник там хороший; есть статьи, хорошие и плохие; есть форум (вот наверно там Вам кто-нибудь что-нибудь подскажет). Информации с javascript.ru мне хватало, а дальше я просто гуглил. На stackoverlflow уже заданы все вопросы и есть все ответы.
          Ответить

Добавить комментарий

Я, guest, находясь в здравом уме и твердой памяти, торжественно заявляю:

    А не использовать ли нам bbcode?


    8