Xiper

Соглашения о коде языка JavaScript

Автор: Валерий Съестов Дата публикации:

Это набор соглашений и правил, которые необходимо соблюдать при написании кода на JavaScript. В основе этого соглашения лежат документы корпорации Sun, для языка программирования Java. Но так как JavaScript это не Java - документ был переработан относительно языка JavaScript.

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

Соглашения о программном коде, может помочь в повышении качества выходной продукции, и снижает вероятность выхода ее из строя.

JavaScript файлы

Программы на JavaScript должны храниться в .js - файлах.

JavaScript код не должен быть встроен в HTML файлы, если код не является специфичным для одной сессии. Код в HTML значительно увеличивает вес страницы без возможности уменьшения за счет кэширования и сжатия.

<script src=filename.js> тэги должны быть размещены по возможности в конце документа. Это уменьшает задержки при загрузки html страницы.

Отступы

Отступы должны состоять из четырех пробелов. Поэтому для написания кода, нужно настроить свой редактор, чтобы табуляция содержала именно такое количество. Использование такого количества символов может повлиять на размер файла, но эта проблема решается путем сжатия файла перед запуском продукта в использование.

Длинна строки

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

В отступлении от соглашения, учитывая современные мониторы и разрешения, длину строки можно увеличить до 120 символов. Современные редакторы кода, делают подсветку этой линии, к примеру NetBeans, PHPStorm, и ее длину можно настраивать.

Комментарии

Необходимо стараться в полной мере давать описания сложным участкам кода. Разработчики, которые будут смотреть на ваш код, или вы сами через некоторое время должны понимать, что этот код делает. Комментарии должны быть хорошо написаны, ясно, корректно, если комментарий недостаточно полный, а еще хуже - ошибочный, который может ввести разработчика в заблуждение, в таком случае лучше не писать комментарий вообще.

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

i = 0; // Set i to zero.

Еще одним из полезных свойств комментариев, что при написании их в определенных правилах, например JSDoc, они могут использоваться для генерирования документации программного кода.

Объявление переменных

Все переменные должны быть объявлены перед их использованием. JavaScript не требует таких конструкций, но при этом программу намного легче читать и это дает возможность легче обнаруживать не объявленные переменные, которые могут подразумеваться интерпретатором как глобальные. Предполагаемые, неявные глобальные переменные никогда не должны использоваться, все переменные должны объявляться только явным способом, и использованием оператора var.

Конструкция var должна идти первой в теле функции.

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

var currentEntry, // currently selected table entry
      level,              // indentation level
      size;              // size of table

В JavaScript нет блока объявления переменных, как к примеру это присутствует в таких языках как pascal, но для того чтобы соблюдать порядок в коде, лучше объявлять переменные в начале функции.

Использование глобальных переменных, должны быть сведены к минимуму, а неявное объявление глобальных переменных вообще не должны использоваться.

Объявление функций

Все функции должны быть объявлены до их использования. Внутренние функции могут объявляется через var. Это помогает прояснить, какие переменные включены в области функции.

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

function outer(c, d) {
    var e = c * d;
    function inner(a, b) {
        return (e * a) + b;
    }
    return inner(0, 1);
}

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

div.onclick = function (e) {
    return false;
};
that = {
    method: function () {
        return this.datum;
    },
    datum: 0
};

Использование глобальных функций, так же должно быть сведено к минимуму.

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

var collection = (function () {
    var keys = [], 
          values = [];
    return {
        get: function (key) {
            var at = keys.indexOf(key);
            if (at >= 0) {
                return values[at];
            }
        },
        set: function (key, value) {
            var at = keys.indexOf(key);
            if (at < 0) {
                at = keys.length;
            }
            keys[at] = key;
            values[at] = value;
        },
        remove: function (key) {
            var at = keys.indexOf(key);
            if (at >= 0) {
                keys.splice(at, 1);
                values.splice(at, 1);
            }
        }
    };
}());

Имена

Имена переменных или функций могут быть составлены из 26 больших и маленьких символов (A .. Z, a … z), 10 разрядов цифр (0 .. 9) и символа подчеркивания. Лучше избегать использования международных символов, потому что их чтение и понимание может внести определенные затруднения. Не используйте знак $ (знак доллара) или (обратную косую черту) в именах переменных и функций.

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

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

Функции конструкторы, которые для работы используют оператор new должны начинаться с большой буквы. Во время компиляции JavaScript сценария, или проверки кода сторонними инструментами будут показывать предупреждения, если функции или имена переменных будут использоваться без конструкции new. Работа функции-конструктора которая не использует оператор new будет вести себя абсолютно иначе, по этому, соглашение о написании таких функций с большой буквы является в некоторой степени защитой от ошибки.

Глобальные переменные, которые носят в себе смысл констант, пространства имен - должны быть заглавными буквами, так как в JavaScript отсутствуют подобные конструкции.

Операторы

Простые операторы

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

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

Составные операторы

Составные операторы - это операторы которые содержать в себе списки других операторов, заключенных в {} (фигурные скобки).

  • Операторы внутри составных операторов должны иметь отступ в четыре пробела.
  • {(Левая фигурная скобка) должна быть в конце строки, в которой начинается составной оператор.
  • } (Правая фигурная скобка) следует ставить на новую строку и с отступом, для выравнивания с началом строки, содержащей соответствующую {(левая фигурная скобка).
  • Фигурные скобки должны присутствовать всюду где возможно их присутствие, это необходимо для избежания случайных ошибок, и для удобства чтения кода.

Метки

Наличие меток break и continue в коде может быть использованы только в конструкциях while, for, do и switch.

Оператор return

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

Оператор if

Конструкция if должна иметь следующий вид:

if (condition) {
    statements
}
if (condition) {
    statements
} else {
    statements
}
if (condition) {
    statements
} else if (condition) {
    statements
} else {
    statements
}

Оператор for

Оператор for должен иметь следующую конструкцию:

for (initialization; condition; update) {
    statements
}
for (variable in object) {
    if (filter) {
        statements
    } 
}

Первая форма записи служит для работы с массивами и циклами с заданным числом итераций.

Вторая форма используется в случае работы с объектами. Нужно иметь в виду, что члены которые добавляются к прототипу объекта, буду включаться в перечисление. Для этого нужно использовать проверку с помощью метода hasOwnProperty, что бы отличить истинные свойства объекта:

for (variable in object) {
    if (object.hasOwnProperty(variable)) {
        statements
    } 
}

Оператор while

Конструкция while должна выглядеть следующим образом:

while (condition) {
    statements
}

Оператор do

Оператор do должен выглядеть следующим образом:

do {
    statements
} while (condition);

В отличии от других заявленных составных операторов, этот всегда должен заканчиваться ; (точкой с запятой).

Оператор switch

Оператор switch должен выглядеть следующим образом:

switch (expression) {
case expression:
        statements
    default:
        statements
}

Каждая ветка case должна быть на одной линии с оператором switch. Это позволяет избегать чрезмерных отступов.

Каждая группа операторов case, кроме default должна заканчиваться break, return или throw.

Оператор try

Оператор try должен выглядеть следующим образом:

try {
    statements
} catch (variable) {
    statements
}
try {
    statements
} catch (variable) {
    statements
} finally {
    statements
}

Оператор continue

Избегайте использования оператора continue. Этот оператор имеет тенденцию скрывать поток выполнения функции.

Оператор with

With оператор не должен использоваться.

Пробелы

Пустые строки улучшают читабельность путем разделения кода на секции которые логически связанные между собой.

Пробелы должны использоваться в следующих случаях:

  • Ключевое слово с последующей ( (левая скобка) должны быть разделены пробелом
    while (true) {
  • Пробел не должен ставиться между именем функции и ( (левой скобкой), в конструкции function f(). Это помогает различать ключевые слова и вызов функции.
  • Все двоичные операторы, кроме . (точки), ( (левой скобки) и [ (левой квадратной скобки) должны быть разделены пробелом.
  • Каждая ; (точка с запятой) в контрольной части конструкции for должна быть разделена пробелом.
  • Пробелы должны следовать после каждой запятой.

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

JSLint. Инструмент для проверка JavaScript кода

Язык JavaScript это интерпретируемый язык, который не имеет своего компилятора, по сравнению с такими языками как Java, C++, который бы при сборке проекта или перед запуском проверял бы качество написанного кода, учитывая различные нюансы, такие как объявленные но неиспользуемые переменные, не оптимизированные участки кода, пропущенные точки с запятой, и т.д. По этому было бы полезно иметь инструмент, который бы выполнял проверку и указывал разработчику на различные погрешности.

Одним из таких инструментом и есть JSLint. JSLint - это программа написанная на JavaScript, назначение которой заключается в поиске проблем в программах JavaScript.

Когда C был еще молодым языком, было несколько распространенных ошибок программирования, которые не отлавливались примитивными компиляторами, так, была разработана программа под названием lint, что бы сканировать исходный файл для поиска ошибок.

Когда язык дошел до определенного уровня совершенства, компиляторы стали лучше его проверять и выдавать соответствующие сообщения после чего, программа lint стала не нужна.

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

JSLint берет исходный код JavaScript и сканирует его. При нахождении проблемы, возвращается сообщение с ее описанием, и приблизительное ее месторасположение в исходном файле. Проблема не обязательно может быть ошибкой синтаксиса, так же проводится проверки стиля, соблюдение структуры кода.

Глобальные переменные

Самая большая проблема в JavaScript - это зависимость от глобальных переменных которые были объявлены неявно. Если переменная не объявлена с помощью конструкции var, то в JavaScript эта переменная становится глобальной, как свойство объекта window. Из за этого могут возникать различного рода ошибки.

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

Иногда файл зависит от глобальных переменных и функций, которые определены в другом месте. Для этого необходимо такие переменные описать в специальной директиве /*global */, которая указывать JSLint что они используются в других файлах и не являются ошибочными. Переменные в директиве представляют собой список имен разделенные запятыми. Каждое имя может включать двоеточие, после которого устанавливается флаг true или false, что указывает, была ли переменная предназначена для этого файла, или нет.

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

/*global clearInterval: false, clearTimeout: false, document: false, event: false, frames: false, history: false, Image: false, location: false, name: false, navigator: false, Option: false, parent: false, screen: false, setInterval: false, setTimeout: false, window: false, XMLHttpRequest: false */

В том числе и console, alert, функции которые могут переопределяться глобально, или которые можно расширить, или которые желательно избегать в конечном продукте.

/*global alert: false, confirm: false, console: false, Debug: false, opera: false, prompt: false, WSH: false */

Точка с запятой

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

JSLint ожидает, что каждый оператор должен заканчиваться ; (точкой с запятой), исключения в некоторых ситуациях могут быть только для операторов for, function, if, switch, try и while.

Запятая

Оператор запятая, может привести к чрезмерно сложным выражениям и так же может маскироваться некоторые ошибки программирования.

JSLint ожидает увидеть использование запятой в качестве разделителя, но не в качестве оператора (за исключением инициализации и приращения частей оператора).

Область видимости

Во многих языках, блок определяет свою область видимости. Переменные объявленные в этом блоке не видны за его пределами.

В JavaScript, блоки не определяют область видимости. Область видимости определяется только внутри функции. Переменная определенная в функции будет видна всюду в этой функции. Блоки в JavaScript могу в этом плане запутать опытных программистов других языков, из за похожего синтаксиса, что соответственно может привести к ошибкам.

В языках с областью видимости в блоках, как правило, рекомендуется объявлять переменные в том месте, где они непосредственно используются. Но поскольку JavaScript не имеет блочной области видимости, правильно будет объявлять все переменные вверху функции. Рекомендуется использовать один оператор var в фукцнии. Эта рекомендация может быть отключена с помощью опции vars.

Обязательные блоки

JSLint предполагает наличие в конструкциях if, while, do и for операторных скобок, в независимости от того, какое количество операторов внутри этих конструкций присутствует.

JavaScript разрешает следующий способ записи:

if (condition) statement;

Эта форма записи, как известно, способствует появлению ошибок в проектах. По этому JSLint предполагает использование следующей записи:

if (condition) { 
    statements; 
}

Опыт разработчиков показывает, что такая форма записи является более устойчивой от ошибок.

for in

Цикл for in используется для перечисления всех свойств объекта. Но так же с помощью этого цикла просматриваются абсолютно все свойства, включая те которые были унаследованы через прототип. Получается плохой побочный эффект, когда в качестве свойства мы получаем метод. Если такой цикл написан без осознания этой ситуации, то этот участок кода может вызывать ошибку.

Тело цикла должна быть обернуто в оператор if, который выполняет проверку свойства объекта, для исключения свойств прототипа, например:

for (name in object) { 
    if (object.hasOwnProperty(name)) {
         .... 
    } 
}

В большинстве случаев, этого оператора стоит избегать полностью. Лучше всего полагаться на методы, такие как Object.keys и Array.prototype.forEach.

switch

Распространенной ошибкой в операторе switch, является то что забывается размещение break после кострукции case. JSLint ожидает, что каждая конструкция case будет заканчиваться break, return или throw. Каждая конструкция case будет выстраивается на одной линии с оператором switch.

var

JavaScript позволяет определять var в любом месте внутри функции. JSLint в этом случае более строго относится к таким определениям.

JSLint ожидает, что конструкция var будет объявлена только один раз, и до того как будет использована.

JSLint отрицательно смотрит на использование конструкции var внутри операторных скобок, так как они не имеют своей области видимости.

with

Эта конструкция изначально была предназначена для обеспечения сокращенного доступа к свойствам глубоко вложенных объектов. Использование этот конструкции может привести к путанице между использованием переменных и свойств, что может дать непредсказуемое поведение программы. По этому, лучше никогда не использовать этот оператор.

== и !=

== и != операторы выполняют приведение типов перед сравнением. Это плохо, потому что различные конструкции, к примеру такая " trn" == 0 будет true. Это может маскироваться ошибки. JSLint не может достоверно определить, если использование == в настоящее время оправдано, по этому лучше всегда использовать сравнение без неявного приведения типов, а именно === и !==.

С помощью опции eqeq, можно отключить проверку этого оператора.

++ и --

JSLint против использования этих операторов. Включить их спользование можно с помощью опции plusplus.

Битовые операции

В JavaScript нет типа Integer, но есть битовые операторы. Битовые операторы преобразуют операнды с плавающей точкою в целые и обратно, поэтому они не так эффективны как в C или других языках. Они редко бывают полезными в браузерных приложениях. Сходство с логическими операторами может маскировать некоторые ошибки программирования. Опция bitwise разрешает использовать эти операторы.

Eval это зло

Функция eval (и его родственники - setTimeout и setInterval) обеспечивают доступ к компилятору JavaScript. Это иногда необходимо, но в большинстве случаев это указывает на наличие очень плохого стиля программирования. Функция eval является наиболее неправильной особенностью JavaScript.

Конструкторы и new

Конструкторы - это функции, которые предназначены для использования с оператором new. Эта приставка создает новый объект на основе прототипа функции, и связывает этот объект функции с присваиваемой переменной. Если принебречь использованием оператора new для функции конструктора, то возвращаемый результат будет не совсем таким, который ожидался.

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

Использование оператора new с такими объектами как Number, String, Boolean - будет считаться ошибкой при проверке.

При проверке такой конструкции new Object, JSLint будет подразумевать ее ошибочной, вместо который лучше использовать краткую запись - {}.

Опции

JSLint предлагает несколько опций, которые контролируют его работу. В веб-приложении JSLint, варианты выбираются с использованием флажков и двух полей.

Когда JSLint вызывается как функция, он принимает параметр - объект опций, который позволяет определить приемлемое подмножество JavaScript. На веб-странице версия JSLint.

Опции можно также задать в сценарии с помощью / * JSLint * / директивы:

/*jslint nomen: true, debug: true, evil: false, vars: true */

Описание Опция Значение
Tolerate assignment expressions ass true if assignment should be allowed outside of statement position.
Игнорирование битовых операторов bitwise true, если битовые операторы не должны проходить проверку
Разрешить функции браузера browser true, учитываются стандартные глобальные переменные браузера
Разрешить Google Closure идиомы closure true, если Google Closure аннотации должны быть разрешены
Разрешать continue continue true, для того что бы использование countinue игнорировалось
Предложение CouchDB couch true, если нужо что бы функции CouchDB считались глобальными
Разрешать debgger debug true, если оператор debug должен быть разрешен
Разрешать console, alert devel true, если не установлена опция browser, и нужно что бы эти операторы были разрешены
Разрешить == и != eqeq true, если == и != операторы должны быть разрешены
Разрешить eval evil true, если eval должен быть разрешен
Пробелы и отступы indent Количество пробелов которые используются для отступов (по умолчанию 4)
Максимальное количество ошибок maxerr Максимальное количество предупреждений для отчета проверки (по умолчанию 50)
Максимальная длинна строки maxlen Максимальное количество символов в строке
Использование прописных букв в начале слова в названии конструктора newcap true, если первые буквы в именах функций конструктора являются обязательными
Учитывать Node.js node true, если Node.js должна учитываться в глобальных переменных
Разрешать прочерк _ в индентификаторах nomen true, если не нужно разрешить использование таких переменных
Остановка на первой ошибке passfail true, если сканирование должно останавливаться на первой ошибке
Разрешить ++ и -- plusplus true, если использование ++ или -- должно быть разрешено
Разрешить отсутствие "use strict" в начале функции sloppy true, для того что бы вставка строки "use strict" была не обязательной
Разрешить TODO комментарии todo true, для того что бы не реагировать на TODO комментарии
Разрешить неиспользуемые параметры unparam true, не показывать предупреждений о неиспользуемых параметрах
Разрешить использование множества var в функции vars true, для множественного использования var в функции
Разрешать грязные пробелы white true, для игнорирования грязных пробелов

Описание работы JSLint, можно посмотреть на официальном сайте