Как стать автором
Поиск
Написать публикацию
Обновить

Комментарии 48

Странно, что не упомянут молодой, довольно богатый и хорошо расширяемый eslint.
function test() {
 myVar = 'Hello, World';
 console.log(myVar);
}


Стоит заметить, что чтобы избегать таких ошибок, можно просто включить строгий режим используя «use strict», и уже сам браузер выдаст ошибку "'myVar' is not defined."

Мне нравится подход кофискрипта в этом — они просто отключили глобальные переменные. Насовсем. К этому быстро привыкаешь и понимаешь, что глобальные переменные по сути не нужны. А те редкие (крайне) моменты, когда они всё-таки нужны (обычно для пост-отладки (не дебаггером в реал тайме) в инкапсулированном коде) достигаются простым присваиванием какому-нибудь глобальному объекту, например
window.someVar = 'somVal'
Сколько ни пытался настроить jsHint под себя, так ни разу и не осилил этот путь до конца. Точнее, не совсем так. Я сталкиваюсь с каким-нибудь предупреждением, которое, на мой взгляд, не уместно. Но не имею рычагов воздействия… Попросту не хватает флагов (хотя их много), либо не все флаги работают так, как я ожидаю от них. В конечном счёте встаю перед задачами: либо полностью подстроиться под jsHint, и писать такой код, который его устроит, что мне кажется, уже очень не правильно, либо вмешаться хирургически. Так и живу с правленными исходниками :)

Кстати, немалой части проблем можно избежать просто воспользовавшись «use strict»;
Во-первых, есть специальные комментарии, которые отключают данный ворнинг для данного куска:
/*jshint -W106 */
save_state(id);
/*jshint +W106 */

(номер ворнинга виден из собственно репорта об ошибке), или для данной функции:
function helloEval(str) {
    /*jshint evil:true */
    eval(str);
}


Во-вторых, попробуйте eslint, он гибче.
Так же посоветую jscs — от отвечает только за форматирование, но консистентное форматирование тоже важно.
Про комментарии в курсе. Но не считаю целесообразным их применять. jsHint это инструмент, не более того. Особенно если над проектом работает несколько человек, и только 1 из них использует jsHint. К тому же расхождений между моим представлением о правильном, и мнением jsHint очень много. С самими кодами у меня была какая-то проблема, ибо изначально я ограничивался только кодами в конфиге (точно уже не помню), но это не хватало.

Во-вторых, попробуйте eslint, он гибче.
Так же посоветую jscs — от отвечает только за форматирование, но консистентное форматирование тоже важно.
Спасибо. Посмотрю на досуге.
несколько человек, и только 1 из них использует jsHint
вот в этом проблема, а не в jshint:)
jshint-комментарии в коде, кстати, дополнительную полезную инфу несут, не только для jshint.
Типа «да, здесь на первый взгляд написано не совсем правильно, но конкретно здесь так надо».
НЛО прилетело и опубликовало эту надпись здесь
Приглядитесь к букве v в названии переменной.
НЛО прилетело и опубликовало эту надпись здесь
Исправьте «статистические» анализаторы в заголовке. Пишу специально не в личку (как с обычной опечаткой), чтобы и другие люди понимали, что «статический анализатор» и «статистический анализатор» — это разные вещи.
Спасибо за замечание. Это таки опечатка)
JSHint как-то странно отреагировал на классику жанра (определение значения по умолчанию):
function main(name) {
  if (name == null) {
     name = 'World!';
  }
  return "Hello, " + name;
  
}
main();


выдал
One warning
13 Use '===' to compare with 'null'.

Хотя это всего «внимание», и вообще в остальном JSHint офигителен и несусветно помогает =)
классика всё-таки
name = name || «default»;
Для переданных false и 0 поведение будет неожиданным.
Ещё пустая строка и NaN (да, порой надо понять, что пришёл именно он, а не просто ничего не передали).

Это классика жанра ошибок, т.к. именно в таких определениях значений по умолчанию частенько делают ошибки (а не потому что способ в принципе ошибочный).

Да, 3 строчки кода вместо одной, зато фундаментальнее. (= А минификатор и так сожмёт =)

Слава богу никто не предложил
if (varDef == undefined) 
или
if (varDef === void 0)
Ну, так и NULL с Undefined могут быть допустимыми значениями. Остаётся только в arguments копаться.
Вы правы и не правы. null может, а undefined — отчасти (начиная с ES5) и то, это следует избегать похлеще сравнения с приведением.
Да, остаётся копаться или менять кусок логики работы со значениями по умолчанию.
Поэтому (не с потолка взято, тот же кофе, тот же типо, тот же дарт) значения задают, сравнивая текущее значение с null

coffee
Если, кстати, писать на кофе и нужно задать параметр внутри логики, удобно можно писать так

param = defaultValue unless param?

и вообще проблемы описанные в этой и следующей статье (все кроме цикломатики) кофескрипт отлично решает =)
Как именно кофе задаёт?
TypeScript например так:

function func(x = 5) {
return x * 3;
}

function func(x) {
if (x === void 0) { x = 5; }
return x * 3;
}

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

func = (x = 5) -> x * 3


var func;

func = function(x) {
  if (x == null) {
    x = 5;
  }
  return x * 3;
};
Добавьте в код /*jshint eqnull:true*/.

(А лучше добавьте это в .jshintrc, если в вашем проекте более одного файла)
Эти слова бы да в статью =)
Так-то в курсе, что настраиваемо, даже так и поступаем, странно, что об этом ни слова.

Просто удивило, т.к. это единственное, с чем можно сравнивать с приведением типов и это корректно, но хинт ругнулся =)
НЛО прилетело и опубликовало эту надпись здесь
А если, положим, надо различить аргумент, который не передали, от аргумента, вместо котого явно передали null или false? Везде свои камни.
НЛО прилетело и опубликовало эту надпись здесь
Я встречал кейс с null. Механизм arguments.length тоже может дать сбой, если, например, два необязательных параметра (util.method('str', undefined, null)).

никогда не знаешь, что придёт от бэкенда
каков поп, таков и приход бэкенд, таков и фронтенд, видимо.
НЛО прилетело и опубликовало эту надпись здесь
Что за «никогда не знаешь, что придёт от бэкенда»? Экстерминейт! Экстерминейт!
Ничто не мешает ручками приводить типы и это полезно: таким образом вы покажете другим прогерам, что тут точная типизация невозможна.
Да, кода много
if ( (var1.toString() === var2.toString()) { /* ... */ }

но очевидно, да и можно сократить и ужать =)
НЛО прилетело и опубликовало эту надпись здесь
Если логика строится на недоверии внешним данным (большинство случаев), то при несоответствии данных представлению ошибка или обработка данного несоответствия обязана произойти (обязаны написать).
То, что вам кажется убожеством или нелепостью не менее, чем хороший стиль написания кода.

Разумеется, если Вы «ловите» ошибки из-за точного сравнения, и, значит где-то код говно, то не следует держаться хорошего и строгого стиля. Так же, как копать колодец во фраке не стоит. Вопрос применимости.

Можете объяснить как == спасает от TypeError при получении метода у неопределённой переменной или null o__O?
НЛО прилетело и опубликовало эту надпись здесь
Вы правда считаете, что тройное равенство уместно, особенно, когда методов (у null и undefined) может и не быть?
Что тогда имелось в виду?

Впервые слышу, чтобы строгий код был говном. о__О Вот если типы хоп и изменились, значит нет тестов, значит что-то в том процессе воняет.
Программист просто не знает возможностей языка и пишет абы не было чего. С обратным результатом, невежество сказывается.
Судя по тому, что пишите Вы, возможностей языка не знаете как раз Вы. Возможно, Вы помните всю таблицу сравнений и приведений типов. Это, возможно, хорошо. Но не все хотят держать это мессиво в голове, куда проще производить строгое сравнение. Если после рефакторинга меняется интерфейс, ему следует измениться во всех местах, иначе… oldNumberNewStringVariable += 11 или наоборот oldStringNewNumberVariables.length простейший артефакт, который из-за отсутствия проверок типов данных создаст баг.

Так что Ваше «проще» выливается в очень странную и неустойчивую конструкцию.
Приводить типы так и так придётся. А === говорит, что тут всё строго, проверено. Это не просто удобно. Это скорость разработки и дисциплина.
НЛО прилетело и опубликовало эту надпись здесь
Строгое сравнение есть атрибут строгого кода.
Про изобретателя JS не понятно к чему, хотя на данный момент есть сомнения, что нет людей знающих JS лучше его изобретателя (много понавесили уж)

Сложного? Да вот ниже описывался пример с пустым массивом и пустой строкой. И таких плюшек, если память не изменяет, ещё штуки три. + вся таблица того же МДН.

Не увиливаю, коли тема приведения типов и сравнения. И правда, кто мешает? Приведи типы и сравнивай точно.

Он приведён ниже, этого достаточно =) Неустойчивость именно в непредсказуемости в пограничных ситуациях. Пустая строка и ноль (закодировалось так или иначе, мы же не верим данным), void 0 и null (не пришло вообще и пришло, что «здесь пусто»)

Ни капельки не выдумываю типичный кодстайл. Вот установки от первоисточника:
www.w3schools.com/js/js_conventions.asp общие правила
www.w3schools.com/js/js_best_practices.asp рекомендации
НЛО прилетело и опубликовало эту надпись здесь
Вот пример реальной баги, которую я исправлял. Функция для удобства принимала на вход либо строку, либо массив строк. В начале была проверка if(param == ""). Всё шло хорошо, пока не передали пустой массив.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Идея в том что от сервера должна приходить или строка или число или массив или объект или что-нибудь еще, но всегда одного и того же типа. Плавающий тип — это всегда спагетти в коде, возможные ошибки и куча лишних проверок, которых можно было бы избежать будь у сервера строгий контракт.
НЛО прилетело и опубликовало эту надпись здесь
> Если раньше, например, парсер просто передавал строку, а потом в новой версии стал распознавать числа, сразу отвергать данные что-ли?

Ну а если вам вместо строки массив или объект прилетит — тоже можно не переживать? Протокол поменялся ведь, в этом случае или версирование используют, или клиента переписывают.
По-поводу операторов — "==" или "===" — это два разных оператора с разной моделью поведения и используемых обычно в строго определенных ситуациях.

Кстати, toFixed для форматирования предназначен, а не для округления. Для округления используют Math.round.
НЛО прилетело и опубликовало эту надпись здесь
i++ можно заменить на i += 1

JSLint тоже сначала показался слишком жёстким, но потом привык :)

У JSHint был плохой парсер. Например:

for (k in obj) {
if (obj[k] === 5) {...}
}

Здесь должно быть предупреждение, типа «юзайте if (obj.hasOwnProperty(k))», но JSHint проверял только на то, что после for сразу стоит if.
Может исправили, не знаю.
А ещё он не умел
switch(variable)
{
  case 'some': { /* code */ }.

Т.е. отдельный блок кода внутри case. Может быть уже умеет. А недавно наткнулся на критичность этого момента в случае использования let. Для let нужен безопасный изолированный блок кода.
JSLint не только жесткий, он еще и заточен под Крокфорда. Крокфорд, конечно, крутой дядька, но не во всем с ним можно согласиться.
Признаюсь, что смотрел я довольно поверхностно, но JSLint мне показался не жестким, а просто дурным.
Он выдает такую кучу бесполезных варнингов, так много ругается на нормальный код, что невольно привыкаешь смотреть на эту кашу по диагонали. И редкие действительно серьезные вещи пропускаешь.
Хочу отметить, что JSLint — это один js-файл на 4000 строчек с комментариями. Там очень классный парсер, который описан в отдельной статье (мой перевод). В парсере строится полное синтаксическое дерево с полезными аннотациями (например, списки переменных, доступные в каждой области видимости). Я к тому, что JSLint легко форкнуть, расковырять, убрать ненужные диагностики и добавить новых по своему вкусу.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий