Замечательный 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:
Лучшая благодарность автору — ваши комментарии!
декабря 9, 2011 at 12:28 (#)
>> 7. Используйте всегда многострочные комментарии.
С комментариями ты перегибаешь. Всегда использую только строчные и ни один минификатор на этом не обламывается.
декабря 9, 2011 at 12:52 (#)
17. Используйте CoffeScript, чтобы не думать о х$$$$, которая написана выше.
декабря 9, 2011 at 13:46 (#)
Kirill, CoffeeScript большей частью решает синтаксические недочеты JavaScript. Что касается вложенных функций, методов, кэширования — все это актуально и для CoffeeScript’а.
декабря 9, 2011 at 14:04 (#)
Даже добавлю в избранное.
декабря 10, 2011 at 09:58 (#)
сокращения => синтаксический сахар (так понятнее)
влаживать => вкладывать
января 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
С остальным полностью согласен.
марта 10, 2012 at 22:06 (#)
по поводу ===, хорошей практикой является писать «по умолчанию» именно ===, а == писать только тогда, когда логика программы требует сравнения с возможным приведением типов.
Несколько удивило, что в пункте 11 требуют отказыться от querySelector из-за проблем с кроссбраузерностью, однако рядом, в 10 пункте советуют использовать относительно новые типы «Int16Array, Int32Array, Float32Array и Float64Array»
марта 10, 2012 at 22:33 (#)
Евгений, согласен с вами. Здесь приведена компиляция рекомендаций из разных источников и в той или иной мере с ними можно спорить.