Убираем лишние запятые из javascript-кода

VIM*
Когда пишешь на js, часто возникают ситуации, когда то тут, то там остаются строчки вида ",)" или ",}" или ",]". В ff, chrome код с такими фрагментами работает, а вот в IE нет.

Лекарство для вима:

autocmd BufWritePre *.js :%s/\(.*\),\(\s*\n*\s*\)\(\}\|\]\|)\)/\1\2\3/e

Регулярка написана на коленке, но она работает и фиксит большинство проблем с запятыми по коду.

Дополнения приветствуются!

UPD:

Такой подход хоть и фиксит большинство рядовых случаев, но также может попортить код с регулярками или, например, строками:

var a = "[,]";
var a = /[,]/;


превратится в:

var a = "[]";
var a = /[]/;


Если в вашем коде есть регулярки и/или строки с похожими конструкциями, то лучше использовать jslint для валидации. Для вима можно использовать github.com/hallettj/jslint.vim
+20
24 февраля 2011, 18:09
24
uzver 4,8

комментарии (44)

+2
Kluyg #
а можно сделать так, чтобы конструкции вида

«width»:42, // my favorite number
}
тоже отлавливались?
0
TEHEK #
С помощью одних только регулярок — никак. Контр-пример для тех, чья мышка уже нависла над крестиком.

var a = 

// "

{
width: "42", // my fav number , ,
url: "http://example.com/image",
}
+4
alisey #
Наверное, тогда уже лучше какой-нибудь JSHint. Как-то не греет душу, когда без моего участия что-то автоматом переписывается.
0
alisey #
Например, регулярку может ненароком переписать.
+2
TheShock #
Угу. Автор даже может протестировать: /[,]/g
0
uzver #
спасибо, подумаю как это можно включить в регулярку.
0
Mezomish #
Про круглые скобки тоже не забудьте: /(\w+,)/
0
uzver #
раньше я использовал обвязку к jslint для вима: github.com/hallettj/jslint.vim, но она сильно подтормаживает, если ее вызывать для каждого сейва.
0
w999d #
спасибо за наводку на форк jslint
+3
widowmaker #
> Когда пишешь на js, часто возникают ситуации, когда то тут, то там остаются строчки вида ",)" или ",}" или ",]".
Скорее всего не когда пишешь, а когда копипастишь, что само по себе уже нехорошо и оставляет много мест для багов, в т.ч. с лишними запятыми. Лучше в данном случае не копипастить, а писать с нуля и использовать подсказки IDE.
+4
TimTowdy #
когда копипастишь, что само по себе уже нехорошо и оставляет много мест для багов
Вы издеваетесь? У меня есть огромный массив огромных хэшей, и я решил в него добавить ещё парочку таких же, с несколькими изменёнными полями. Я весь хэш буду руками набирать? По-вашему это не оставляет много мест для багов? Во всяких перлах-питонах для того и разрешили в конце списка/хэша ставить запятые, чтоб облегчить копипаст. Не путайте копипаст кода с копипастом данных.
0
widowmaker #
Мне кажется вам надо сменить подход, дублирование это о-о-очень плохо. У вас не возникало ощущения что вы делаете что-то не так, когда копируете большой хэш и меняете в нем пару значений? А что если в каждый хеш надо будет добавить еще одно одинаковое значение — тоже Ctrl+C, Ctrl+V?
0
b0n3Z #
Я не копипащу «огромные хеши», однако эта фича действительно удобна при разработке. При возможности можно быстро добавить новый элемент и браузер не поругается из-за того, что вы забыли поставить запятую.
Подход Питона правилен в данном случае.
0
TimTowdy #
дублирование это о-о-очень плохо
Еще раз говорю, не путайте дублирование кода и дублирование данных. Из миллиона юзеров только два имеют разный пол, остальные 999998 — продублированный. И страна у 90% продублирована. Откройте код хабра и посмотрите сколько продублированных структур — на каждый комментарий, где отличается только юзер, дата, и содержимое, дублируется целая страница текста. И это нормально, потому что это данные, а не выполняемый код.
0
widowmaker #
Дублирование плохо даже для данных, поэтому были придуманы РБД. Страницы же на хабре всей базы не содержат, лишь выборку нужную для отображения, поэтому тут нету дублирования 999998 одинаковых полов. Если у вас много хэшей различной сложности, что мешает их генерировать скриптом из бд, это удобнее и быстрее в перспективе, хотя первичные затраты времени и большие. Вообще программист должен быть ленив, а ленивого программиста тяжело заставить заниматься ручным дублированием и заполнением данных, поэтому программист пишет программку которая сделает рутину за него.
Собственно, именно из-за того что дублирование данных нехорошо — при сайтостроении начали использовать скрипты чтобы не дублировать тысячи html-файлов изменяя их немного.
0
apkawa #
Данные для js могут генерироваться динамически, и из за того, что в запятые в конце не ест IE, то приходится делать типа так:

var some_var = {
{% for key, value in some_dict.iteritems %}
{{key}}: "{{value}}"{% if not forloop.last %},{% endif %}
{% endfor %}
};
0
widowmaker #
Это какой-то шаблонизатор? В PHP есть замечательная функция json_encode, которая не генерирует лишних "," да еще и экранирует все вредные символы, например переносы строк в строках и кавычки.
0
b0n3Z #
Это Django.
Кстати, да, apkawa, почему бы не создать json.dumps? Достаточно создать template tag соответствеующий и все.
+3
TimTowdy #
Ага, в небольшое приложение, которое хранит настройки в JSON, я внезапно должен подключать реляционную базу данных (минимум пару сотен Кб для сжатого sqlite), делать несколько нормализованных таблиц чтобы избежать ужасного дублирования (сэкономлю пару сотен байт!), и генерировать оттуда этот JSON. И это всё для того чтоб прочитать настройки. Спасибо, поржал.

А что если в каждый хеш надо будет добавить еще одно одинаковое значение — тоже Ctrl+C, Ctrl+V?
Да, «yy», потом несколько раз «p» (vim же). А в вашем случае — что я буду делать если мне понадобится из некоторых хешей удалить/поменять значение? Писать код который генерирует хеши по шаблону, потом код который заменяет/добавляет нужные ключи в нужных хэшах, потом код который удаляет нужные ключи. А потом когда другой человек захочет добавить поле ХХХ в объект УУУ, он должен будет разбираться как этот код работает? И весь этот геморрой вместо использования данных, которые самоочевидны, только потому что дублирование это очень плохо?

Вот вам условный пример кода с огромным количеством дублируемых данных:
{
    "values": [
        {
            "name": "first",
            "a": "value1",
            "b": "value2",
            "c": "value3"
        },
        {
            "name": "second",
            "a": "value1",
            "b": "value2",
            "c": "value3"
        },
        {
            "name": "third",
            "a": "value42",
            "b": "value2",
            "d": "value3"
        },
        {
            "name": "last",
            "a": "value1",
            "b": "value2",
            "c": "value42",
            "d": "value4"
        }
    ]
}

Нужна возможность максимально быстро сделать следующее:
1. Изменить «b» во втором объекте.
2. Удалить «b» из третьего.
3. Добавить «e» в последний.
4. Скопировать «a» из первого в третий.
5. Быстро сказать значения в «a» и «d» в третьем объекте.

Мой рутинный копипаст позволяет сделать всё вышеперечисленное. Жду от вас код, который позволит делать то же самое быстрее, и избежать копипаста/дублирования.
–1
widowmaker #
Ага, в небольшое приложение, которое хранит настройки в JSON, я внезапно должен подключать реляционную базу данных (минимум пару сотен Кб для сжатого sqlite), делать несколько нормализованных таблиц чтобы избежать ужасного дублирования (сэкономлю пару сотен байт!), и генерировать оттуда этот JSON. И это всё для того чтоб прочитать настройки. Спасибо, поржал.

А ржать не надо, я ж не говорил что в приложении надо подключать бд или еще что-то. Я имел в виду то, что генерировать готовый конфиг можно самописной тулзой.

Вот вам условный пример кода с огромным количеством дублируемых данных.

Слишком условный, но в данном случае можно храниить данные в более удобном виде:
{
   "valueDefaults" : {
      "a": "value1",
      "b": "value2",
      "c": "value3"
   },
   "values": [
      {
         "name": "first"
      },
      {
         "name": "second"
      },
      {
         "name": "third",
         "a": "value42",
         "c": null,
         "d": "value3"
      },
      {
         "name": "last",
         "c": "value42",
         "d": "value4"
      }
   ]
}

В «values» хранится только дифф. Обработка поменяется не сильно, можно даже сразу фором пройтись и смёржить данные, это не столь важно. Зато потом будет визуально нагляднее, чем каждая из них отличается.
+2
TimTowdy #
В результате:
  • добавляем в последний объект пару «a»:«value42» — возвращается неизбежная дублируемость, исчезает упомянутая вами наглядность (смотрим на последние два объекта)
  • пишем дополнительный код, который мёржит и удаляет
  • теряем возможность хранить null, либо другое «специальное» значение
  • с первого взгляда непонятно что хранится в объекте — нужно сначала смотреть на default, потом в уме мёржить хэши (представьте что они в 5 раз больше)
  • добавляя новый объект, нужно помнить что у нас в default, чтоб не забыть проставить null лишним ключам
  • удаляя ключ, нужно помнить нет ли его в default — если есть, то ставить null, если нет — просто удалять
  • вполне возможна ситация когда остаётся куча дублирования, а default не сократит код, а только увеличит, например [{«a»:1, «b»:«2»}, {«a»:1, «c»:3}, {«b»:2, «c»:3}]
  • усложняем структуру, вводим дополнительную логику — другому человеку сложнее разобраться
  • копипаст особо никуда не исчез, да еще и усложнился — добавьте пару «f»:«value5» в первые два объекта: либо копипастим её в эти объекты, либо добавляем в default и проставляем null в остальных объектах

В общем кода стало больше, действия которые я описал стали выполняться дольше, понимать эту структуру сложнее. Не вижу ни одного преимущества.
0
bolk #
В JS тоже можно оставлять запятые в конце. Просто старые IE этого не поддерживают.
+1
widowmaker #
По стандарту нельзя, поэтому приходится подчищать. Кстати не только IE не любит такой код, лишние запятые нужно обязательно удалять если передавать данные в JSON, парсер либо сгенерирует предупреждение либо скажет что данные невалидные. Это как незакрытый тег в XML.
0
TEHEK #
Стандарт допускает такие «висячие» запятые.
0
widowmaker #
Допускает только для массивов. Но речь идёт еще и об объектах и аргументах
0
TheShock #
0
uzver #
Согласен насчёт писать с нуля и использовать подсказки IDE, но во-первых эта запись в блоге про vim (к слову о подсказках), а во-вторых ситуации с запятыми часто возникают в длинных hash-like конфигурациях, например для extjs компонент, когда убираются ненужные флаги (или временно комментируются).
+1
vsviridov #
Пишите в хаскель-стиле:
var object =
{
a:"a"
,b:"b"
,c:"c"
}
0
uzver #
Да, это один из выходов, но он хуже воспринимается визуально. Хотя впрочем все зависит от принятых соглашений по оформлению кода в команде.
0
vsviridov #
Зато можно комментировать индивидуальные записи и не париться из-за свисающей запятой…

var object = {
    a: "a"
    //,b: "b"
    ,c: "c"
}
+1
itlife #
Зато теперь надо беспокоиться, о запятой в начале при скрытии первой строчки.
В центре в любом случае можно безопасно комментировать… ;)
0
vsviridov #
Ну, выгоднее по любому :)
+3
TheShock #
тогда так:
var object = { a: "a"
             , b: "b"
             , c: "c"
             }
0
gopline #
1001 и одна причина похоронить IE
–1
uzver #
Вы не поверите, но IE следует стандарту ECMAScript (т.е. IE в этой ситуации больше соответсвует стандартам, чем другие браузеры).
+1
TheShock #
Как раз согласно стандарту эту запятую оставлять можно.
+3
TheShock #
Пруф. Пункт 11.1.4:
Если в любом месте списка элементов встречается запятая, перед которой не присутствует ВыражениеПрисваивания (т. е. запятая в начале списка или сразу после другой запятой), пропущенный элемент массива увеличивает длину объекта Array и индексы последующих элементов.

смотрим код:
[1,2,3,]

Последняя запятая не в начале списка и не после другой запятой. Перед запятой присутствует выражение присваивания.
+3
uzver #
Вы правы :), спасибо за выдержку из спеки.
+1
uzver #
Правы, но только по части массивов, для инициализации объектов такой синтаксис стал допустим только с ES5.
т.е.
+1
uzver #
foo = {bar: 'baz',
tom: 'cat',
}


для ES3 невалидна.
0
TheShock #
кажется, в спеке про запятые в объектах вообще не описано.
+1
uzver #
да в в спеке я этого с ходу не нашел, зато нашел описание бага в мозилле, где есть косвенная ссылка на этот факт bugzilla.mozilla.org/show_bug.cgi?id=508637
0
dmitry_dvp #
Для поиска описанных запятых пользуюсь галочкой «строгие предупреждение» в web-developer@firefox
image
0
dmitry_dvp #
Виноват. Проверил — не показыват ошибки. Раньше показывал, чем многократно пользовался

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.