Замечательный JavaScript ч.2: Хорошие практики

декабря 9, 2011  |  Published in ClientSide, JavaScript  |  8 Comments

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

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

Не правильно

if (true)
  alert(true);

Правильно

if (true){ alert(true); }

2. Всегда ставьте точку с запятой.
В JavaScript ставить точку с запятой в конце каждой строки является необязательным, однако, что произойдет если мы минифицируем код? — Правильно, код поломается.

Неправильно

function myFunction(a,b) {
  var sum = a + b
  alert(sum)
}

Правильно

function myFunction(a,b) {
  var sum = a + b;
  alert(sum);
}

3. Всегда используйте var для объявления переменных и избегайте глобальных переменных.
Если вы не используете var для объявления переменных, то такие переменные объявляются как глобальные переменные. Глобальные переменные несут различные опасности связанные с некорректной работой кода.

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

Неправильно

function myFunc() {
  var name = "",
  lastName = "",
  age;
  /* code here */
  var x = 100500;
  /*code here*/
  for(var i = 0; i < 100; i++){
    /*code here*/
  }
}

Правильно

function myFunc() {
  var name = "",
  lastName = "",
  age,
  x = 100500,
  var i = 0; 
  /* code here */
}

5. Не используйте сокращений.
Сокращения — это сладкий яд, который убивает ваш код.

Неправильно


++i;
i ++;
var a, b = 100, 50;
[javascript]

Правильно
[javascript]
i += 1;
i = i + 1;

var a = 100,
b = 50;

Сокращения делают ваш код менее очевидным, а некоторые, как, например множественное присваивание вообще приводят к ошибкам. В примере с переменными a и b, a будет локальной, а b — глобальной.

6. Используйте === для сравнения вместо ==.
Оператор == в действительности не сравнивает объекты, а пытается привести их типы. Для сравнения объектов в JavaScript используйте оператор ===.

Неправильно

0 == false //true
[] == false //true

Правильно

0 === false //false
[] === false //false

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

Неправильно

var myVar; //myVar хранит myValue

Правильно

var myVar; /*myVar хранит myValue*/

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

Неправильно

for (i=0; i <= myArray.length; i += 1){
  /*some code*/
}

Правильно

var length = myArray.length

for (i=0; i <= length; i += 1){
  /*some code*/
}

Неправильно

$("#my-id").click(function(){/*some code*/});
$("#my-id").dblClick(function(){/*some code*/});

Правильно

var myId = $("#my-id);
myId.click(function(){/*some code*/});
myId.dblclick(function(){/*some code*/});

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

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

Неправильно

var myFunction = function (a) {
  if (a >= 100){
    decrement(a);
  } else {
    increment(a);
  }

  var increment = function (a) { return a -= 1; }
  var decrement = function (a) { return a += 1; }
}

Правильно:

var myFunction = function (a) {
  if (a >= 100){
    decrement(a);
  } else {
    increment(a);
  }
}

var increment = function (a) { return a -= 1; }
var decrement = function (a) { return a += 1; }

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

10. Используйте массивы специальных типов Int16Array, Int32Array, Float32Array и Float64Array.
Когда это возможно — используйте массивы специальных типов. Они работают примерно в 2 раза быстрее обычных. Разумеется, в таких массивах можно хранить только численные значения, однако даже так можно более-менее значительно улучшить производительность вашего кода, особенно если вы работаете с графикой.

11. Используйте getElementsByClassName(), getElementsByTagName(), и т.д. вместо querySelector() и querySelectorall().
В DOM Level 3 были добавлены два замечательнейших метода — querySelector() и querySelectorAll(), которые используются для обращения к элементам DOM используя CSS-селекторы. Это очень отличные инструменты для работы с DOM, однако не стоит ими злоупотреблять. Во-первых они не поддерживаются старыми браузерами (IE6, IE7), а во вторых они медленнее чем getElement… — методы. Частичный отказ от querySelector() и querySelectorAll() позволит вам увеличить производительность и затраты на написание кроссбраузерного кода (кода будет меньше за счет отсутствия некоторых проверок = лучше читабельность, меньше размер, меньше операций — еще больше производительность).

Неправильно

document.querySelectorAll("div");

Правильно

document.getElementsByTagName("div");

12. Переносите методы в прототипы там, где это возможно

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

Неправильно

var MyConstructor(name, age){
  this.name: name;
  this.age: age;
  this.info: function () {
    alert("My name is " + this.name + " and I'm " + this.age);
  }
}

Правильно

var MyConstructor(name, age){
  this.name: name;
  this.age: age;
}

MyConstructor.prototype.info = function () {
  alert("My name is " + this.name + " and I'm " + this.age);
}

13. Не используйте with
with — это совсем бесполезное ключевое слово, которое делает ваш код менее очевидным для любого, кто будет его читать, даже для вас. Кроме того, with может значительно ухудшить производительность.

Неправильно:

with (document) {
  write("Welcome to http://RubyDev.ru!");
  /*etc.*/
}

Правильно:

document.write("Welcome to http://RubyDev.ru");

Как вариант:

var d = document;
d.write("Welcome to http://RubyDev.ru");

14. Используйте ?: оператор для выбора из двух значений, но не для выбора из двух действий.
Эта рекомендация данная Дугласом Крокфордом датируется 2005 годом и обосновывается тем, что использование ?: для выбора одного из двух действий не является кроссбраузерным решением. На сколько это актуально сейчас не знаю, но стоит быть внимательными.

15. Комментируйте ваш код и снабжайте комментарии примерами его использования.
Мне очень нравится как задокументирован код Rails и я видел, что многие Ruby/Rails разработчики, что разрабатывают собственные библиотеки или делаю коммиты используют тот же стиль комментирования. Это очень хорошо, когда код можно читать как документацию.

16. Используйте профессиональный инструментарий и пишите тесты или спецификации.
В работе с любым языком программирования успех программиста и проекта в достаточно большой мерез зависит от инструментария. Работая с JavaScript вы просто обязаны быть знакомым с FireBug и его аналогами для других браузеров, возможно вас заинтересует Firefox Aurora. FireBug и его аналоги предоставляют разработчику несколько полезных инструментов, которые включают в себя консоль JavaScript, отладчик и профайлер. Используя эти инструменты вы сможете быстро находить ошибки и исправлять их, экспериментировать с кодом и замерять производительность для выбора наиболее оптимального варианта. Кроме того, я рекомендую вам использовать инструмент JSLint авторства Дугласа Крокфорда. Этот инструмент предназначен для анализа вашего JavaScript кода и обнаружения в нем опасных моментов. Как альтернатива JSLint существует JSHint — это форк JSLint. Оба инструмента хороши и практически идентичны.

Для тестирования вы можете использовать QUnit или Jasmine. Jasmine — это BDD фреймворк, аналог RSpec для JavaScript разработанный командой PivotalLab. В PivotalLab очень любят RSpec и желали сделать нечто подобное для тестирования/написания спецификаций для JavaScript кода своих приложений. QUnit и Jasmine не единственные инструменты для тестирования, но имхо, самые популярные.

Удачи вам в разработке вашего кода на JavaScript!

UPD:

Лучшая благодарность автору — ваши комментарии!

Tags: ,

Responses

  1. Anton says:

    декабря 9, 2011 at 12:28 (#)

    >> 7. Используйте всегда многострочные комментарии.

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

  2. Kirill says:

    декабря 9, 2011 at 12:52 (#)

    17. Используйте CoffeScript, чтобы не думать о х$$$$, которая написана выше.

  3. admin says:

    декабря 9, 2011 at 13:46 (#)

    Kirill, CoffeeScript большей частью решает синтаксические недочеты JavaScript. Что касается вложенных функций, методов, кэширования — все это актуально и для CoffeeScript’а.

  4. says:

    декабря 9, 2011 at 14:04 (#)

    Даже добавлю в избранное.

  5. says:

    декабря 10, 2011 at 09:58 (#)

    сокращения => синтаксический сахар (так понятнее)
    влаживать => вкладывать

  6. says:

    января 31, 2012 at 23:12 (#)

    >>сокращения => синтаксический сахар (так понятнее)
    >>влаживать => вкладывать

    Забавно выходит. Автор, получается, советует не использовать синтаксический сахар? Непонятно, «i++» — учат писать на C во всех вузах. i+=1 — тоже сокращение и синтаксический сахар. Видимо, автор советует избегать путаницы с i++ и ++i, но если человек знает язык, то в чем проблема разобраться в этих сокращениях — непонятно.

    >>Используйте === для сравнения вместо ==.
    >>Для сравнения объектов в JavaScript используйте оператор ===.

    Тоже странный совет. Видимо формулировка и примеры не совсем подходят.
    0 == false
    » == false
    undefined == false

    Это ведь для того и придумано, чтоб я мог проверить, что в левой части нечто… эм… «незначимое». И мне не важно, ноль там, пустая строка или пустой массив(может мне неизвестно заранее что там окажется). И почему пишете «для сравнения объектов»? Называете 0 или false объектом? Если сравнивать именно то, что в javascript принято называть объектом ({a:0} == {a:0}), то там будет false, хоть с двойным «равно», хоть с тройным, а true будет только если мы сравниваем ссылки на один и тот же объект. Например,

    obj1 = {a:0};
    obj2 = obj1;

    obj1 == obj2 //true

    С остальным полностью согласен.

  7. Евгений says:

    марта 10, 2012 at 22:06 (#)

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

    Несколько удивило, что в пункте 11 требуют отказыться от querySelector из-за проблем с кроссбраузерностью, однако рядом, в 10 пункте советуют использовать относительно новые типы «Int16Array, Int32Array, Float32Array и Float64Array»

  8. admin says:

    марта 10, 2012 at 22:33 (#)

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

Leave a Response

Для подсветки кода используйте BB - коды: [language]...[/language], где language может быть: ruby, javascript, css, html.