1. JavaScript / Говнокод #12002

    +160

    1. 1
    new Array(100).map(function(x) { return Math.random() * 1000; });

    Угадайте результат.

    Запостил: wvxvw, 25 Октября 2012

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

    • The array constructor creates an array with the given length. It does not create the keys.
      Мда. Массив длины 100, в котором нет ни одного ключа, и на котором, очевидно, не работают мапы...

      new Array(3) - тут length == 3, все элементы undefined, но мап не видит элементов.
      [undefined, undefined, undefined] - тут тоже length == 3, все элементы undefined, но мап все видит.

      А я думал такой бредовый пиздец это прерогатива с++ и php...
      Ответить
      • Да как-то вообще не понятно зачем нужен такой конструктор. Создавать массив без ключей смысла как бы нет совсем. Что интересно, не смотря на то, что AS3 как бы и реализует ES, на этот аспект они положили, и это позволяет заранее выделить нужное количество памяти (чтобы потом каждый раз не выделять память по-новой). А тут даже если и захочешь, все равно не получится. Вообще бессмысленная херня какая-то.
        Ответить
        • Кстати а for видит эти ключи?

          Отвечу сам себе - нет, тоже не видит. Т.е. этот конструктор мало того, что совершенно бесполезен, так еще и не дает возможность запилить инициализированный массив из одного элемента: new Array(1,2) можно, а new Array(1) - нет.
          Ответить
          • for (var i in new Array(5)) console.log("i = " + i);

            Неа.
            Ответить
          • Не знаю почему, но вспомнилась "оптимизация 3" http://habrahabr.ru/post/133104/ :)
            Ответить
            • Какие прекрасные имена...
              console.time('qwe');
              console.time('asd');

              P.S. Уже третий линк на хабр за сегодня.
              Ответить
              • >Уже третий линк на хабр за сегодня.
                метастазы
                Ответить
            • >оптимизация 3
              во всех кинотеатрах страны
              Ответить
            • Да как-то печально это все. Сервер на котором человек боится запустить 30 игр одновременно? Нужно делать какие-то оптимизации и бороться с неявными проявлениями языка.
              На заре моей програмистской карьеры мне довелось писать клиент к "бинго" игрушке, конечно, игра очень простая, но и не совсем рандом. Т.е. конечно, рандом, но инфраструктура привязаная к сюжету занимает больше, чем сюжет. "Сервер" к этой игре слабал какой-то народный зодчий на С#, работало оно плохо даже по тогдашним представлениям, и код был вообще ужас. Но 3-4 тысячи клиентов в пиковые часы обслуживал.
              Ответить
              • Вот и меня это ужаснуло. До "оптимизации" вообще всего 2-3 было, а нода штука не медленная, хоть и прожорливая. Видать, подобная работа с массивами - не единственный серьезный косяк автор, нужно в сорцах покопаться.
                Ответить
                • Ну он пишет что и исходящий канал у него 200кб\с. А танчики все-таки не пошаговая игрушка.

                  P.S. 20-30 игр это получается 80-120 человек, если они играют 2х2.
                  Ответить
                  • Канал - да, но 30 игр, что 8мибитная nes тянула, на Intel Pentium 4 3.00GHz для полной загрузки процессора...
                    Ответить
    • Всё ломают на говнокоде... То Пайтон, то Хаскель, теперь вот и до Жаваскрипта добрались. Что будет через пять лет?
      Ответить
    • function makeArray(size, initialElement) {
               return new Array(size).join(",").split(",").map(
                   function() { return initialElement; });
      }

      Зато можно так :)
      Ответить
      • только зачем?
        Ответить
        • Для того, чтобы запутать наиболее вероятного противника. join() почему-то считает, что элементы есть, а map() - что нету.
          Ответить
          • Ну это ясно... Только, если не учитывать шпионов, куда проще сделать так (если вообще такая функция может кому-то пригодиться):
            function makeArray(size, initialElement) {
              var a = new Array();
              for (var i = 0; i < size; i++) {a[i] = initialElement;}
              return a;
            }

            А еще можно в качестве второго параметра передавать функцию, которая будет вычислять значение элемента массива в зависимости от его индекса.
            Но на самом деле всё это не нужно.
            Ответить
    • Зато в Firefox начиная с 16-й версии работает так (благодаря spread-оператору из ECMAScript Harmony):

      [...new Array(100)].map(function(x) { return Math.random() * 1000; });


      Или даже просто так:

      [...new Array(100)].map(function() Math.random()*1000);
      Ответить
      • Ну, явное улучшение! Хорошо так, добротно починили. Так что мой вариант со split/join теперь даже не кажется говнокодом.
        Ответить
        • Как я понял, спред всё-таки не ради этого внедрялся.
          Ответить
          • Ну, как бы радует то, что появилось больше способов выполнить произвольный кусок текста как код, и еще больше запутать интерпретатор / самих программистов.
            Это мало кто знает, и никто не пользуется, но, например, 2 точки подряд в жабоскрипте используются в одном случае, когда у литерала числа в десятеричном представлении нужно вызвать какую-то функцию. Т.е. 100..toString() например, а в неутвержденном, но реализованом E4X те же две точки значать выборку всех наследников у XML / XMLList.
            Ну а с появлением трех точек, возможно появятся смешные опечатки. Особенно принимая во внмимания большую нелюбовь жабоскриптеров к синтаксису в целом игнорирование пробелов в частности.
            Ответить
            • >появилось больше способов выполнить произвольный кусок текста как код, и еще больше запутать интерпретатор / самих программистовпоявилось больше способов выполнить произвольный кусок текста как код, и еще больше запутать интерпретатор / самих программистов
              It's new sport game for programmers.
              Ответить
            • А где тут текст?
              Ответить
            • Пардон, понял, что речь идёт не о вредоносном коде в строковом представлении. Но не понял, при чём тут пробелы.
              Ответить
      • выглядит жутко
        Ответить
      • И зачем все эти извращения? Чтоп все в 1 строчку? Так, банально, даже короче будет:
        for(var a=[],l=100;l--;)a.push(Math.random()*1000);
        console.dir(a);
        Ответить
        • Но ценой инициализации переменной, тогда как искомое однострочное выражение само разрешается в требуемое значение.
          Ответить
          • А [...new Array(100)].map(fn) создает и инициализирует 2 вспомогательных массива.
            Первый new Array, второй [], а возвращается тот, что создается map.
            Ответить
            • Но ни одна переменная в пространстве имён не занимается, а результат можно подставлять в этой же строчке.
              Ответить
        • Вот что смешно, например, так то, что если бы массив был реализован так, как нормальному человеку кажется, что это нужно сделать, то никто никогда бы не делал в той ситуации как у вас array.push() - у вас же уже индекс массива есть, осталось только записать, а push делает кучу всего, и считает элементы, и память может выделить и весь массив скопировать если понадобится и т.д. Но в жабоскрипте - фиолетово. Что еще интереснее, менее известные реализации жабоскрипта потом на этом обламываются, и понимают, что реализовать хорошую и быструю стратегию нельзя, а нужно делать так, чтобы работало у большинства...
          Ответить
          • Гмм, похоже я ненормальный, т.к. то, что в свое время я прочитал в спецификации о массивах в js, 1 в 1 совпало с моим представлением о них:) push не так уж и много кроме put делает - разве что length инкрементирует - http://es5.javascript.ru/x15.4.html#x15.4.4.7

            Представленный выше велосипед:
            1. Создаём пустой массив и устанавливаем его длину в 100.
            2. Создаём из этого массива List(массив аргументов) из, соответственно, 100 элементов, каждый из которых будет undefined.
            3. Создаём еще один массив через [] с сотней аргументов undefined.
            4. Получаем массив из 100 элементов undefined.
            5. Создаём еще один пустой массив и устанавливаем его длину в 100.
            6. Создаём калбэк, возвращающий рандомное значение, помноженное на 1000.
            7. 100 раз проверяем наличие элемента во 2ом массиве, если есть запускаем калбэк с этим значением, пишем результат по такому-то индексу в конечный массив.

            Велосипед с push:
            1. Создаём пустой массив и переменную, инициализированную в 100.
            2. 100 раз декрементируем значение переменной, пишем рандомное значение, помноженное на 1000, в массив и инкрементируем его длину.
            Ответить
            • А при чем здесь это? Я говорю про создание массива по-настоящему, виртуальной машиной, а не то, что вы делаете в жабоскриптовском коде. Жабоскриптовский код по-определению не показатель. Например, в том же AS изза некоторых деталей реализации массивы работают по-другому, и соответственно, такой код, как выше на порядок хуже (а не на чуть-чуть), чем запись по индексу.
              Ответить
              • Ну это не жабаскрипт код, а алгоритм из спецификации. Конечно, реализация на совести создателей движка. В них не копался, но про выделение памяти - цитата из статьи про оптимизацию производительности в v8: "Не заполняйте предварительно большие массивы (содержащие больше 64K элементов) — это ничего не даст." Что-то я не уверен, что большинство движков, как ES6 научатся, все эти лишние действия 1го алгоритма выкинут.
                Ответить
                • Так тогда описанного выше не происходит на самом деле. Более того, Массив на 100 елементов никогда вообще в принципе ни одной из мейнстримных реализаций жабоскрипта (кроме AS) не создается. То, что описано выше вообще не похоже на то, что происходит на самом деле.
                  Ответить
            • Попробую объяснить:
              push - вызов API функции, который предполагает кучу разных проверок, оберток, он и системное время прочитает, и может даже какие-то временные объекты в памяти разместит и т.д. Т.как это функция с варируемым числом аргументов, то и для аргументов еще обертка есть.
              Типично предполагать, что динамические массивы будут выделять память постепенно, удваиавая ее. Т.е. если вы начнете с массива с нулевой длиной, то он будет расти когда вы добавите в него второй, четвертый, восьмой и т.д. элементы, конечно, в реальности начинает расти с каких-нибудь пары тысяч, т.как выделяется с запасом в рассчете на то, что жабоскриптерам особо большие массивы все равно ни к чему, то, в принципе, догадка неплохая.
              Таким образом, если вы не записываете просто по индексу значение, вся эта механика усложняется тем, что нузно каждое какое-то время перевыделять память под массив, копировать и т.д.
              Далее, память под массив, по крайней мере в AS выделяется при создании, и выделяется ее столько, сколько было указано в конструкторе, таким образом последующие записи по индексу становятся элементарными операциями. В случае с жабоскриптом, получаем что таких примитивных операций просто нет, т.как нельзя предварительно заготовить память, и пользоваться push - вобщем-то то же самое, что и записывать по индексу.
              Еще большая лажа начинается, когда в массиве пропущены элементы, и часть массива существует в памяти как массив, а часть, - как хеш-мап, и там тоже свои усложнения, с которыми push так или иначе столкнется, хеширование ключей, слежение за тем, чтобы "сумки" куда ключи складываются не наполнялись выше какого-то определенного предела - все это не нужно при обычной записи по индексу.
              Ответить
              • Упс, не обновил:) Ну мой ответ выше. Так-то да, иногда, когда памяти не будет хватать, их нужно будет пересоздавать, но не на сотне элементов.
                Ответить
                • Ну так фишка в чем, пока жабоскрипт - это игрушечный язык, на котором что-то работает, пока оно в тестовой песочнице, и массивы не большие, и хеш-мапы не нужно пересоздавать. А когда "вдруг" возникает необходимость типа ноды, оказывается, что за такие вещи потом жестоко наказывают. Если вдруг окажется что в одном массиве нужно держать списки друзей друзей каких-нибудь фейсбуков у тысячи пользователей, а потом этими массивами нужно будет манипулировать в том же ключе, как это делает браузерный жабоскрипт - тут-то все и развалится.
                  А в браузерном жабоскрипте никто и не замахивается на какие-то серьезные вещи. Даже какой-нибудь примитивный редактор звука - уже облом изза плохой, по определению и задумке реализации массивов. А видео редактора на жабоскрипте мы, при нашей жизни, скорее всего и не увидим никогда.
                  Ответить
                  • Ну да, слишком высокоуровневый - слишком многое за ширмой, слишком мало действительно больших проектов - мало на грабли наступали. Многое необходимое отсутствует, надеюсь, ES6 ситуацию поправит. Кстати, в огнелисе на 1000000 элементов оба велосипеда прогнал - скорость совпадает до статистической погрешности.
                    Ответить

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