Pull to refresh

Comments 107

>Обязательно использовать break после каждого case

Бывают моменты кода, где необходимо чтобы несколько case выполняли одно и тоже, при этом легче написать

case 1:
case 2:
case 3: function(); break;

чем писать везде

case 1: function(); break;
case 2: function(); break;
case 3: function(); break;

Поэтому мне кажется данный пункт не совсем актуальным.
Согласен, бывает и такое. JSLint ругается больше чем надо, этим и ценен. Лучше обратить внимание на его замечание и проигнорировать, чем не обратить внимание на ошибку.
С этим согласен, просто в тексте статьи это звучит очень категорично и может ввести в заблуждение.
UFO just landed and posted this here
JSLint не ругается на первый пример.

Видимо, автор топика имел в виду «после каждой группы case». Иногда после последней группы не ставят break, иногда позволяют специально потоку выполнения «проваливаться» в следующую группу… И вот это линту не нравится.
Всё верно. JSLint требует чтобы перед case ставился либо break либо case.
Цитата из выступления Дугласа Крокфорда:
Однажды кто-то написал мне: «В языке есть оператор switch, в котором можно проваливаться из одного case-выражения в другое, и это достаточно трудно увидеть, читая код. Не могли бы вы добавить предупреждение в JSLint для таких случаев?». Я подумал и ответил, что есть моменты, когда подобные провалы могуть быть удобными. Можно прямо в коде помечать, что так и задумывалось, хотя на самом деле, вы знаете, это не работает. Возможно, в качестве компромисса имеет смысл оставить всё как есть. В конце концов, неплохо иметь такой оператор в языке.

На следующий день тот же парень прислал мне сообщение об ошибке в работе JSLint. Я запустил отладчик и обнаружил ошибку в switch-операторе, где case-выражение проваливалось в следующее. [Смех в зале.]

В тот момент ко мне пришло озарение. В карьере программиста бывают моменты, когда вы действительно что-то постигаете. И это постижение трудно даётся. Тогда я получил урок. Теперь я никогда сознательно не даю case-выражениям проваливаться. Благодаря этому я сейчас могу легче замечать случайные провалы case-выражений. Как следствие, я думаю, что моё использование switch-оператора значительно улучшилось.
UFO just landed and posted this here
Во-первых side-effects. Чтобы код можно было сжать точки с запятой должны стоять везде где надо. В javascript необязательность точки с запятой иногда достигается за счет того, что перевод строки считается за разделитель.
Во-вторых, при командной работе важен единый стиль. Код оформленный правильно, выглядит надежнее и в нем лучше видны ошибки.
UFO just landed and posted this here
Если уже выработан командный стиль, подразумевающий отсутствие точек с запятой, то тут уж не попишешь ничего — придется следовать. Но это ограничит рамки команды людьми которые либо уже в команде, либо не особо опытны в javascript и не имеют привычки ставить точки с запятой. Это касательно командной работы.

Касательно yui сказать не могу, т.к. пользуюсь другими инструментами (packer, jsmin), которые требуют расстановки запятых. Не знаю, можно ли доверить машине расставить точки с запятой.
В Ассемблере; применяется для комментариев (TASM, MASM) (-:

;=======
mov [(t ZoomPanel edi).hWnd], eax
;=== создаю ReBar
sub edx, edx
push edx [hInst] edx
push eax
;---
push edx edx; Размеры
push edx edx; Координаты

mov eax, WS_CHILD or WS_VISIBLE or WS_CLIPSIBLINGS or\
WS_CLIPCHILDREN or RBS_VARHEIGHT or CCS_NODIVIDER
push eax
push edx
push ofs strReBarClass
push WS_EX_TOOLWINDOW
Call CreateWindowEx
or eax,eax
jz @@exitErr
;======

по сути, можно в конце строк ставить, как в js — ничего плохого не будет (-:

Писал длинный коммент, а браузер его скинул, обидно. Придётся кратко.

Я за то, чтобы компрессоры кода выкидывали не перевод строки, а точку с запятой, тогда код меньше терял бы в читаемости и проще было бы понять где нашлась ошибка.
UFO just landed and posted this here
А что такого особенно хорошего в отсутствии точек с запятой? Их отсутствие не дает ничего, вы даже код без них писать быстрей не будете. А вот элементарно вытянуть код в строчку с удалением пробелов, чтобы он места меньше занимал, вы уже не сможете.
UFO just landed and posted this here
многие просто пишут не только на JS, поэтому точка с запятой переходит из других языков, с их стороны это тоже в основном дело привычки, как и с Вашей
Точка с запятой, отбитая руками:

— упрощает работу javascript-интерпретатора;
— позволяет достаточно безопасно сжимать код, удаляя пробелы/переносы;
— улучшает читабельность кода, код выглядит профессионально (уж точно в js-среде);
— набивает руку для работы с другими языками, где (;) часто обязательна;
— снижает риск потенциальных ошибок при работе AIS.
от того что Вы вытянете код в строку, он меньше «места» занимать не будет
Почему не смогу, объясните? Точка с запятой без перевода строки — один байт, перевод строки без точки с запятой — один байт.
Банально код с точками-запятыми выглядит более читабельно
UFO just landed and posted this here
не выглядит, он выглядит, банально, так же, только без точек с запятыми
Точки с запятой иногда помогают при нахождении синтаксических ошибкок в коде, таких как незакрытые скобки. Без точек с запятой часто консоль ошибок показывает ошибку в последней строке, а вот с ";" уже видно где что незакрыл.
А вот случай из моей практики для защиты точек с запятыми.
Как-то раз написал для проекта кучку jquery-плагинов и других ништяков. И лежало всё добро по отдельности, по неймспейсу на файл, например, в виде:
(function($){ /*ништячный плагин*/ })(jQuery)

В один прекрасный момент, решил тулзой собирать классы в один файл, чтобы разом отправлять скрипты клиенту. Собрал пакет, сжал с помощью YUICompressor. А ништяки-то и не работают.
Потому что получилась каша:
(function($){ /*плагин 1*/ })(jQuery)(function($){ /*плагин 2*/ })(jQuery) и т.п.
С тех пор, ставлю ';' в начале и конце файла.
UFO just landed and posted this here
> С тех пор, ставлю ';' в начале и конце файла.

Кстати, если поговорить о «сферических конях в вакууме», то распространённая практика с постановкой точки с запятой вначале (в качестве страховки на случай, если автор предыдущего скрипта не поставил её в конце), действительно, действенна. Однако, если точка с запятой была правильно поставлена в конце скрипта, то ваша точка с запятой вначале создаст Empty Statement, и, соответственно, будет сканироваться, парситься и «тратить время» ;) Но это так — к слову. На практике же, да, вероятно, удобно при использовании нескольких 3rd-party библиотек и скриптов.
Cогласно Ecmascript определённые statements must be terminated with semicolons, точка с запятой обязательна с точки зрения языка, но опциональна для программиста. Если вы выбрали путь опциональной точки с запятой, то вы выбрали путь, где нет ясности, парсер начинает крутиться за вас, автоматически их «расставляя», по сути он исправляет ошибки. В древних доках Javascript это называли эквивалентом compile-time error-correction. К тому же парсеры не всегда делали это правильно, были и баги на этот счёт (может и сейчас есть), сами dev-ы языка настоятельно рекомендуют не полагаться на AIS и ставить всё руками.

Если же говорить о стиле и вкусовщине, то за всё время работы с javascript я встречал принципиальных борцов за лысый правый край всего раза два. Отчаянные белые вороны. Зато принципиальные. ;-)
UFO just landed and posted this here
UFO just landed and posted this here
Ну так Вы и в качестве принципиального борца не выступаете :) Так что не стоит принимать на свой счёт ;-)
UFO just landed and posted this here
IE не любит запятые после последнего элемента массива или члена объекта. Бывает, что именно на это и указывает jslint: var a = [1,2,3,]; Хотя для других браузеров все ок.

Думаю, количество предупреждений зависит от реализации. Плагин для jEdit у меня выдает 51 ошибку, потом останавливается с фразой — слишком много ошибок.
вообще это стандарт ецдма говорит что в массивах и обьектах после последнего элемента не должно быть запятой, так что в данном случае ИЕ делает правильно =)
В объектах — да, в массивах — нет.
Вы уверены? массив в JS — обьект, и он обязан следовать тем же стандартам что и обьект
:-) Не обязан и не следует. И да… уверен.
Да, очень это напрягает =) Особенно когда напишешь много кода, а он потом валится в IE (т.к. отлаживается в FF). Самое обидное, что дебаггер номер строки с ошибкой отдает от балды, даже, иногда, на другой файл ругается.
спасибо за статью. теперь буду более пристальней проверять свой джаваскрипт код.
очень интересная статья, спасибо!
Только один вопрос:
Может быть в конструкции:
----------
var f = function (x) {
setTimeout(function () {
console.log(x);
}, 0);
}
for (x = 1; x < 10; x += 1) {
f(x);
}
----------
стоит поставить точку с запятой по примеру:
----------
var f = function (x) {

};
----------
?
Вы правы.
Надо бы встроить в браузер JSLint, чтобы показывал ошибки такого рода :)
Объясните популярно почему при выполнение этого кода в ФФ сразу пишет одно число (не смотря на таймаут), а только потом (уже согласно таймауту) все остальные?
for (x = 1; x < 10; x += 1) {
    setTimeout(function () {
        console.log(x);
    }, 1000);
}
потому что цикл выполниться сразу, без задержек
и создаст в очереди 10 функций, которые ссылаются на глобальную для них переменную Х
которая соответственно в этот момент уже равна 10
Вы не ответили на мой вопрос. Переформулирую:
Попробуйте лучше это:
for (var x = 1; x < 2; x += 1) {
    setTimeout(function () {
        console.log('x = ' + x);
    }, 2000);
}
'stop';

Первый вывод — это результат выполнения команд в консоли, который получается немедленно, далее — то что по таймеру.
Спасибо за объяснение. Действительно, выписывается последнее значение, которое возвращает setTimeout

for (var x = 1; x < 12; x += 1) {
     setTimeout(function(){}, 2000);
}

Я могу предположить что он видя function выполняет её, затем ставит таймаут, посредствам которого выводит оставшиеся числа. С чем связано такое поведение, остаётся только догадываться.
какой смысл в if ((x = y)) {

сокращение кода на одну строчку и необходимость обернуть блок кода в кавычки?
Иногда так пишут чтобы визуально показать неотделимость блока от результата выполнения какой-то функции. Например
if ((result = try_to_fetch_result())) {
    do_something_with_result(result);
}
Кстати я замечал у джавистов и сишников полезную привычку — в if'ах сначала писать константу при сравнивании:
if (SOME_CONSTANT == var) {…

if ('text' == str) {…

Такая конструкция идет несколько коробит восприятие (я так подозреваю, что только сначала, во время привыкания), но значительно уменьшает вероятность провести много времени в жестоком дебаге из-за = вместо ==.
Ну насколько я помню, такая привычка больше связана с вероятностью, что переменная может быть пустой. И тогда оператор == может вызвать ошибку, так как не определён для пустого объекта. В случае же, когда сначала пишется константа, она является вполне конкретным объектом, для которого оператор сравнения определён. И эксепшена не будет.
На самом деле, это защита от опечаток, когда вместо == ошибочно набирают =.
Например, следующий код скомпилируется, но условие никогда не выполнится:
int a = getValue(); if (a = 0) { /*code*/ };
А если поставить константу в начало, то компилятор выдаст ошибку о том, что операция присваивания не валидна:
int a = getValue(); if (0 = а) { /*code*/ };
Что-то мне подсказывает, что Вы ошибаетесь. Оператор == униполярный, т.е. нет никакой разницы в порядке указания операндов. И если один из них не определен и в силу особенностей языка не сможет быть в таком виде приведен к какому-то сравнимому с другим типу, то ошибка произойдет в любом случае, будь он слева или справа. А вот ошибиться и присвоить переменную вместо сравнения легко.
Очевидно, мои воспоминания идут из каких-то совсем давних времён. Ибо с описанной мною проблемой сталкивался лично, но как-то очень давно.
Спасибо, буду использовать.

Как он к коду jquery относится? Я имею ввиду если писать с использованием методов jquery, он их валидирует, плюёт или кучу варнингов выдаёт?
Для использования jQuery я пишу /*global jQuery, $ */ и JSLint не ругается. По сути же jQuery — это две глобальные переменные, не на что там больше ругаться. Вообще говоря, по jQuery и правилам хорошего тона использования можно еще целую статью написать.
Хорошая вещь, но, ИМХО, фанатично верить ей тоже не стоит.
Как правильно сказано — не панацея.
На некоторые вещи Линт ругается с видом цепного пса, которому кидают косточку по одной за каждый гавк.)
Удалось ли заставить JSLint не ругаться на неопределённую переменную $? Мне в globals её два года назад не удалось вставить, может что-то изменилось?
/*global $ */ работает для меня
Кстати, неплохобы было прикрутить его как плагин к Eclipse\Aptana\NetBeans\Visual Studio :)
Уже прикручено как минимум в Eclipse\Aptana\NetBeans. Про Visual Studio сказать не могу, так как не юзал. Вот тут говорят, что есть и для VS: www.codeproject.com/KB/macros/JSLintVS.aspx
Поделитесь пожалуйста ссылкой или руководством, как для Eclipse сделать?
Сначала когда только начал писать код на XUL+javascript использовал JSLint чтобы найти синтаксическую ошибку в js-коде. Сейчас javascript-код пишу в Komodo Edit. Он находит и подсвечивает ошибки в коде. Правда конечно не так придирается к коду как JSLint, но зато не нужно туда-сюда копировать код чтобы найти ошибку.
ошибки в коде может и NetBeans подсветить + ошибки css, html, php
В целом довольно логичные и правильные правила. И не только для js.
У меня с линтом связан курьезный и идиотский, на мой взгляд, случай.
При удачном собеседовании и написании тестового задания, я не был принят на работу по причине того, что мой код не прошел валидацию JSLint'ом. По сути там было только одно критичное замечание — я не сделал проверку на hasOwnProperty в конструкции for (var in object). В остальном, «специалист» долго дрючил мне мозги за лишние точки с запятой: после function, for,… и лишние пробелы в конструкциях типа if (element.parentNode && Math.max(offset1, offset2, offset3) > x1).
> При удачном собеседовании и написании тестового задания, я не был принят на работу по причине того, что мой код не прошел валидацию JSLint'ом.

Это не собеседование, а хрень на постном масле. К чёрту такие конторы.

> В остальном, «специалист» долго дрючил мне мозги за лишние точки с запятой

Вы правильно сделали, что ушли оттуда.
Это скорее не контора, а человеческий фактор. Насколько я помню это была компания Oberon Media, один из лидеров казуальных и онлайновых игрушек. И я, честно говоря, весьма хотел там работать, собеседование с HR мне понравилось, деньги и условия предлагали интересные. Скорее всего было как-то так: «Ты! Через 5 мин ты проводишь собеседование». А если человек не знает, как проводить это собеседование и абсолютно не готов к нему, начинается всякий бред.
Большинство правил итак соблюдаю. Единственное, при итерации всегда объявляю переменную в конструкции for, как-то некомфортно мне ее объявлять за пределами, так как используется только внутри.
Качество кода у меня чаще страдает из-за отсутствия модификаторов доступа. Бывает, слишком увлекаюсь, потом объекты наглухо привязаны друг к другу. В последнее время борюсь с этим префиксом "_". Еще иногда увлекаюсь замыканиями, но это как правило легко рефакторится.
иронично, что автор самого JSLint Douglas Crockford сказал следующее: In most of the classical languages, the language is the thing imposing the discipline. In Javascript you have to bring your own discipline.

на русский это переводится приблизительно так: В большинстве классических языков сам язык принуждает к дисциплине. В яваскрипте вам нужна собственная дисциплина.

у меня достаточно собственной дисциплины, чтобы не пользоваться костылями вроде JSLint
> у меня достаточно собственной дисциплины, чтобы не пользоваться костылями вроде JSLint

ага ;)
Ой, да ладно, минусовать-то сразу ;) Я хотел сказать, что не нужно её воспринимать как «спасение» от «выдуманных проблем». В целом же — тулза, конечно, полезная.
Вчера его как раз слушал на конференции. Не впечатлил. Говорил про секурность в браузерах. Так вот, на вопрос «кто использует jslint?», в зале полном веб программистов и дизайнеров поднялось всего 2 руки.
некоторые вещи он правильно говорит
а к jslint отношение разное бывает
Ничего не имею против него, и говорил он правильные вещи о которых я сделал себе пометочки и идеи, которые пришли в голову в тот же момент. Но лично меня он не впечатлил, и предлагаемые решения тоже. И на вопрос «а сколько человек/компаний пользуются вашим решением?» (речь про безопасность веб-приложений) Он ответил — «два — я и ...». Скорее всего хотел пошутить, но думаю он недалек от реального положения дел. Зал тоже не особо бурно реагировал на его выступление. В общем популязатор своих или чьих-либо еще идей он никакой.
> В javascript глобальные переменные можно объявить в локальном контексте, что только усугубляет ситуацию, потому что иногда можно объявить глобальную переменную по ошибке

Касается не столько ошибок объявления свойств глобального объекта, а просто уточнение — переменные объявляются только с ключевым словом var. Обычное же присвоение, создаёт свойство глобального объекта, но не переменную. Соответственно, нельзя объявить глобальную переменную в локальном контексте.

> который может получиться только при помощи правильного использования механизма видимости имен:

Вариант с обрамляющим контекстом (в виде новой внутренней функции) — не единственный, чтобы замкнуть нужное значение. Поэтому слово «только» может смущать. С одной стороны оно может относится с слову «правильного» (и это верно), с другой — может подразумевать, что данный способ — единственный, что неверно.
Не хватает еще упоминания, что JsLint можеть делать проверку на соответствие правилам ADsafe.
Вопрос к автору: а зачем вы выделили тело цикла в отдельную переменную f? Не проще ли было написать

for (x = 1; x < 10; x += 1) {
(function (x) {
setTimeout(function () {
console.log(x);
}, 0)
}(x));
}
Думаю, так понятнее для нубов. Кроме того, JSLint предупреждает, что использовании анонимых функций в циклах. Ваш пример с точки зрения JSLint'a должен быть таким:
for (var x = 1; x < 10; x += 1) {
	setTimeout(function (x) {
		return function () {
			console.log(x);
		};
	}(x), 0);
}
Странно, у меня не ругнулся, вот законченый пример:

/*global setTimeout, console */
for (var x = 1; x < 10; x += 1) {
(function (x) {
setTimeout(function () {
console.log(x);
}, 0);
}(x));
}

(Проверял через сайт; в исходном варианте ругнулся только на точку с запятой и глобальные переменные.)
> Кроме того, JSLint предупреждает, что использовании анонимых функций в циклах

А почему?

Кстати, результат в вашем примере другой будет.
x += 1 вместо ++x это считается за повышение качества кода? ;-)
крокфорд настаивает, что ++ вредно использовать
Вредно чем? Аргумент, что код «too tight, too tricky, too cryptic» не канает вообще, уж для ясного и солнечного for-in точно. Я как это вижу: x+=1, у меня сразу 2 вывода в голове:

a) он не знает операторов;
б) он болеет крокфордизмом.

;-)
не for-in, а for конечно же.
для него этот аргумент канает, может быть, и в случае for тоже
Вкусовщина, в общем. ок
Я болен точно. И, кстати, не только Крокфорд, но и Макконнелл пишут о том что x++ и ++x надо использовать с осторожностью.
Что может случиться в js, если я буду неосторожен и напишу:

for ( var i = 0; i < a.length; ++i ) {

}

Можете остановить на минуту список авторитетов и просто аргументировать. Правда, интересно, почему компактный и ясный оператор в скриптовом языке нужно отбросить.
Произойдет что-то вроде такого:
Человек, возможно не очень хорошо знающий нюансы языка, просматривающий код в поисках чего-то необходимого ему вместо того, чтобы пропустить этот фрагмент в фоновом режиме (что следовало бы делать), споткнется о не совсем понятный ему оператор. У него возникнет вопрос, почему тут используется префиксный инкремент, а не постфиксный. Он усомнится в своих знаниях нюансов языка (быть может). Вруг еще полезет гуглить. В любом случае, поток мыслей его прервется из-за использования нестандартного элемента в стандартной ситуации.

Я, кстати, не против использовать в этом контексте i++. Но, поскольку использую JSLint, пишу без варнингов, просто чтобы не пропустить чего-то действительно важного. Плюсы очевидны — операции инкремента всегда однообразны, что не заставляет читателя кода каждый думать о несущественном с одной стороны, а с другой стороны — дает мне, как пишущему программу, понять, что код — это не место для соревнования, кто хитрее напишет. Лично я против любой самодеятельности типа ++i там где можно обойтись i += 1. Но вообще говоря, если принятый стандарт требует обратного — я буду так же ратовать за использование ++i. Главное, чтобы везде было одинаково и не возникало вопросов, ни как писать, ни как читать такой код.
> В любом случае, поток мыслей его прервется из-за использования нестандартного элемента в стандартной ситуации.

Именно так и случается со мной, когда я в 'for' вижу i+=1 Поток мыслей моих тут же прерывается из-за использования нестандартного элемента в стандартной ситуации. Вы много js-кода видели в таком вот русле крокфордизма? Что стандартней, если считать просто по объёму?

Можно ещё с натяжкой понять про '===' вместо '==', но инкремент внутри 'for' давить безо всяких причин… это перебор. ;-)
В данном случае, согласен, имеет место перегиб. Сейчас перепроверил даже свои настройки — мой JSLint не ругается на ++ и --

Но и ++i в данном контексте сбивает с толку. Согласитесь, что для цилклов стандартнее i++
Для обычного простого 'for' не важно пост или пре. Можно и так, и так. В своё время пре тестили, и он считался более быстрым (чуть другой алгоритм по сравнению с пост), как сейчас — не знаю, тут уж дело привычки.
ничего не имею против ++ /- -, но вчера на конференции(fronteers 2009) в докладе уважаемого Thomas Fuchs следующий кусочек не только меня поставил в тупик:
~~(какие-то вычисления)
Оказалось двойное отрицание — это просто конверсия числа в int. Вместо Math.floor() для экономии размера кода.
> Вместо Math.floor() для экономии размера кода.

Иногда не только экономия размера кода имеет место быть, но и, также, экономия в скорости, как, например, в преобразовании строкового представления в число. Когда однозначно известен формат числа (включая систему счисления), то часто быстрей и удобней использовать ведущий плюс для преобразования (в альтернативу, например parseInt)

var str = '10';
alert(typeof +str); // number
> Человек, возможно не очень хорошо знающий нюансы языка

Ну так а в чём проблема? Значит надо садиться и изучать язык.

Это как, например, математика. Есть школьный уровень. Есть уровень техникума. Университета. Академический уровень.

Так вот, скажите мне, — с какой стати я должен писать на уровне математики 6 класса школы, чтобы код был понят каждым новичком после прочтения книги «Этот занимательный Javascript»? И это не относится сейчас к конкретному случаю с «x++» или «x += 1».

Естественно, основным критерием, в общем случае, должна являться простота чтения кода. Но только не надо перебарщивать, приводя аргументом, что код не поймут новички, которые только прочли первую главу книжки.

В частных случаях, где критерием может быть максимальный выжим ресурсов, могут использоваться нестандартные хакерские способы — но здесь нечитаемость будет уже оправдана.
> крокфорд настаивает, что ++ вредно использовать

Дедушка Крокфорд, действительно, внёс немалый вклад в JS (в основном, прикладного характера). Но только вот не делайте из него «икону», а? Он далеко не безупречен в JS, тоже ошибается, местами знает JS поверхностно, и мысли его порой субъективные.

Если вы будете постоянно «полагаться на истину авторитета, вместо того, чтобы полагаться на авторитет истины, вам будет нелегко» донести свою точку зрения.
я разделяю ваше отношение к крокфорду, хотя и не считаю, что он внёс вклад в JS, кроме JSON
Problem at line 169 character 13: eval is evil.
eval( 'var list = ' + strList );

:-D разработчики с чувствою юмора
Для меня JSLint тоже средство совершенно незаменимое, т.к. сам разрабатываю довольно непростой фреймворк (для карт). Особенно критичны две вещи: точки с запятыми (чтобы код не ломался после сборки различного рода компрессорами — сам пользуюсь рубишным packr, работающим по алгоритму Крокфорда) и отсутствие глобальных переменных (узкоспециализированный фреймворк не может себе такого позволить, чтобы избежать конфликтов с другими).
Sign up to leave a comment.

Articles