Независимо от нашего уровня мастерства, все мы когда-то были новичками. И все мы время от времени можем допустить глупую ошибку. Текущая статья подготовлена авторами Nettuts+, которые были любезны поделиться их списками ошибок и их решениями, в различных языках.
Избегая ошибок в программировании, приведенных ниже, вы сможете существенно повысить качество создаваемого кода!
Советы по JavaScript
1 — Ненужные манипуляции с DOM
DOM медленный. Ограничивая свои манипуляции с ним вы значительно увиливаете производительность своего кода. Посмотрите на следующий (плохой) код:
// anti-pattern for (var i = 0; i < 99; i++){ var li = $("<li>").html("Это элемент списка №" + (i+1)); $("#someUL").append(li); }
Этот код модифицирует DOM 99 раз, и создает 99 ненужных объектов jQuery. Девяносто девять — сумасшедшая цифра! Более правильным решением было бы использовать фрагмент документа или создать строку, содержащую 100 элементов <li/>
, а затем вставить это дело в HTML. Таким образом мы обращаемся к DOM всего один раз. Вот пример:
var liststring = ""; for (var i = 99; i > 0; i--){ liststring += "<li>Это элемент списка №" + (98- i); } document.getElementById("someUL").innerHTML(liststring);
Как было сказано выше, таким образом мы касаемся DOM только один раз, что является улучшением, однако с помощью конкатенации мы получаем довольно большую строку. Вот другой способ которым можно решить нашу задачу, используя массив.
var liststring = "<li>" var lis = []; for (var i = 99; i > 0; i--){ lis.push("This is list item #" + (98- i)); } liststring += lis.join("</li><li>") + "</li>"; document.getElementById("someUL").innerHTML(liststring);
Построение больших строк, храня каждый фрагмент строки как элемент массива и соединяя их с помощью join()
пожалуй более элегантно, чем использование конкатенации. Приведенный способ один из самых быстрых и простых для создания повторяющийся HTML с помощью JavaScript без использования библиотек или фреймворков.
2 — Нелогичные имена Переменных и Функций в JavaScript
Этот пункт не касается производительности напрямую, но очень важен, особенно если вы работаете с кодом, с которым кроме вас работают другие люди. Используйте логичные идентификаторы (имена функций и переменных). Посмотрите на следующий пример:
var foo = "bar"; var plant = "green"; var car = "red";
Нет смысла добавлять переменную с бессмысленным именем, вроде Something
. Это вносит несогласованность в именование переменных, заставляя ваш мозг задумываться обычная ли это переменная или константа. По этой причине константы в большинстве языков, зачастую, именуются заглавными буквами.
Сделайте еще один шаг вперед — поддерживайте похожую длину, грамматическую структуру и пояснительную природу при именовании функций. Для примера рассмотрим следующую, выдуманную функцию:
function subtractFive(number){ return number - 5; }
Называя функцию, которая прибавляет к числу пять и возвращает результат используем тот же шаблон, и получим:
function addFive(number){ return number + 5; }
Иногда можно называть функцию указывая тип возвращаемого результата. Например вы можете назвать функцию которая возвращает HTML именем getTweetHTML()
. Вы также можете предварять название функции словом do
, если функция только выполняет какие-либо инструкции и ничего не возвращает, например: doFetchTweets()
.
Конструктор функции, следуя традициям классов в других языках, называется с большой буквы:
function Dog(color){ this.color = color; }
Основное правило заключается в том, что вы должны давать описательное имя идентификаторам. Старайтесь определять похожие переменные в одном месте, используя один шаблон именования, это улучшит читаемость и подскажет на характер переменной или назначение функции.
3 — Использование hasOwnProperty()
в циклах for...in
Массивы в языке JavaScript не являются ассоциативными; использование их в качестве таких осуждается комьюнити. Объекты, с другой стороны, могут рассматриваться как хэш-таблицы. Такой подход подталкивает к перебору свойств объектов используя циклы for...in
, например так:
for (var prop in someObject) { alert(someObject[prop]); // выдаст значение свойства }
Однако, нюанс в том, что цикл for...in
перебирает свойства прототипа. Это может вызвать некоторые проблемы если вам нужно отобразить только существующие свойства выбранного объекта.
Можно решить эту проблему используя метод hasOwnProperty()
. Вот пример:
for (var prop in someObject) { if (someObject.hasOwnProperty(prop)) { alert(someObject[prop]); // выдаст значение свойства } }
Такой вариант выдаст только значения свойств, находящихся непосредственно в someObject
.
4 — Сравнение булевых переменных
Сравнение булевых переменных это пустая трата вычислительного времени. Рассмотрим это на следующем примере:
if (foo == true) { // делаем что-нибудь если истина } else { // делаем что-нибудь если ложь }
Заметим что: foo == true
. Сравнение foo
и true
не нужно, поскольку foo
и без того булево значение (является ложью или истиной). Вместо сравнения foo
, просто используем его значение, например:
if (foo) { // делаем что-нибудь если истина } else { // делаем что-нибудь если ложь }
Для значения false
, используем логический оператор NOT (НЕ), как показано ниже:
if (!foo) { // делаем что-нибудь если ложь } else { // делаем что-нибудь если истина }
5 — Назначение событий
События сложные объекты в JavaScript. Прошли времена встроенных событий вроде onlick
(за редким исключением). Вместо этого используется делегация событий.
Представьте, что у вас есть «сетка» изображений, которые нужно отображать в лайтбоксе. Вот чего не надо делать. Заметим: мы здесь используем jQuery, надеясь что используете похожую библитеку. Впрочем, эти принципы можно использовать и в чистом JavaScript.
Соответствующий HTML:
<div id="grid-container"> <a href="kakaya-to-kartinka.jpg"><img src="kakaya-to-kartinka-thumb.jpg"></a> <a href="kakaya-to-kartinka.jpg"><img src="kakaya-to-kartinka-thumb.jpg"></a> <a href="kakaya-to-kartinka.jpg"><img src="kakaya-to-kartinka-thumb.jpg"></a> ... </div>
JavaScript (плохой):
$('a').on('click', function() { callLightbox(this); });
Этот код устанавливает вызов лайтбокса всем ссылкам, для просмотра полного размера изображения. Вместо использования всех ссылок, ограничимся элементом #grid-container
.
$("#grid-container").on("click", "a", function(event) { callLightbox(event.target); });
В приведенном коде, и this
и event.target
ссылаются на элемент «ссылка». Данная техника может применяться с любым родительским элементом. Только убедитесь, что правильно выбрали целевой элемент.
6 — Тернарная избыточность
Чрезмерное использование оператора тернаторсти обычное дело как в JavaScript, так и в PHP.
// javascript return foo.toString() !== "" ? true : false;
// php return (something()) ? true : false;
Условия всегда возвращают в качестве значения true
или false
, так что вам нет необходимости дополнительно указывать true
/false
в тернарном операторе. Вместо этого, можно просто вернуть значение сравнения:
// javascript return foo.toString() !== "";
// php return something();
Советы по PHP
7 — Используйте тернарный оператор при необходимости
Оператор ветвления if...else
является основой большинства языков. Но когда нужно сделать что-то простое, например присвоить значение в зависимости от состояния переменной, это не то следовало бы использовать. Посмотрите на следующий код:
if ($greeting) { $post->message = 'Приветик, товарищи!'; } else { $post->message = 'За сим, прощаюсь!'; }
Этот код можно уменьшить до одной строки, не ухудшив его читаемость, используя оператор тернарности, например так:
$post->message = $greeting ? 'Приветик, товарищи!' : 'За сим, прощаюсь!';
Это четко, кратко, и обеспечивает всю необходимую функциональность.
Несмотря на полезность оператора тернаности, главное не переборщить! Ведь цель программирования не в том чтобы уместить всю логику в паре строк кода.
8 — Используйте защищенные классы
Оператор if
в основном используется для контроля пути выполнения функции или метода. Распространенное явление, когда выполняется большой фрагмент кода в случае когда условие true
, и простой возврат значения в операторе else
. Например:
function someFunction($param) { if ($param == 'OK') { $this->doSomething(); return true; } else { return false; } }
Однако, такое решение может сильно усложнить читаемость вашего кода. Вы можете улучшить этот код всего лишь инвертировав условие. Вот улучшенная версия:
function someFunction($param) { if ($param != 'OK') return false; $this->doSomething(); return true; }
Легче читается, не правда ли? Это простое изменение, дающее резкое различие в читабельности кода.
9 — Поддерживайте понятность методов
Это одна из наиболее распространенных ошибок у новичков.
Метод объекта, это единица работы, и ограничение размера методов улучшает поддержку кода у улучшает его читаемость и восприятие. Рассмотрим это на следующем ужасном примере:
class SomeClass { function monsterMethod() { if($weArePilots) { $this->goAndDressUp(); $this->washYourTeeth(); $this->cleanYourWeapon(); $this->takeYourHelmet(); if($this->helmetDoesNotFit()) $this->takeAHat(); else $this->installHelmet(); $this->chekcYourKnife(); if($this->myAirplain() == "F22") $this->goToArmyAirport(); else $this->goToCivilianAirport(); $this->aim(); $this->prepare(); $this->fire(); } } }
Разобьем этот монструозный метод на несколько маленьких, каждый из которых будет предназначен для одной четко определенной задачи. Это одна из наиболее распространенных ошибок у новичков.
class SomeClass { function monsterMethod() { if($weArePilots) { $this->prepareYourself(); $this->tryHelmet(); $this->findYourAirport(); $this->fightEnemy(); } } private function prepareYourself() { $this->goAndDressUp(); $this->washYourTeeth(); $this->cleanYourWeapon(); $this->chekcYourKnife(); } private function tryHelmet() { $this->takeYourHelmet(); if($this->helmetDoesNotFit()) $this->takeAHat(); else $this->installHelmet(); } private function findYourAirport() { if($this->myAirplain() == "F22") $this->goToArmyAirport(); else $this->goToCivilianAirport(); } private function fightEnemy() { $this->aim(); $this->prepare(); $this->fire(); } }
И вуаля наш код стал чище и легче для отладки!
10 — Избегайте большой вложенности
Слишком большее количество уровней вложенности делает ваш код сложным для чтения и обслуживания. Посмотрите на следующий код:
function doSomething() { if ($someCondition) { if ($someOtherCondition) { if ($yetSomeOtherCondition) { doSomethingSpecial(); } doSomethingElse(); } } }
Используя ранее озвученный совет, «развернем» некоторые условия.
function doSomething() { if (!$someCondition) { return false; } if (!$someOtherCondition) { return false; } if ($yetSomeOtherCondition) { doSomethingSpecial(); } doSomethingElse(); }
Этот код определенно лучше для восприятия, а делает тоже что и пример выше.
Если вы замечаете что увлеклись со вложенностью выражений if
, то внимательно посмотрите на свой код; похоже что ваш метод выполняет больше одной задачи. Вот пример:
function someFunc() { if($oneThing) { $this->doSomething(); if($anotherThing) $this->doSomethingElse(); } }
В таком случае извлеките вложенные методы, и объявите их собственные методы:
function someFunc() { if($oneThing) { $this->doSomething(); $this->doAnotherThing($anotherThing); } } private doAnotherThing($anotherThing) { if($anotherThing) $this->doSomethingElse(); }
11 — Избегайте магических чисел и строк
Магические числа и строки это зло. Определяйте переменные или константы со значениями, которые вам хочется применить в коде.
Вместо подобной конструкции:
function someFunct() { $this->order->set(23); $this->order->addProduct('superComputer'); $this->shoppingList->add('superComputer'); }
Укажите, что эти числа и строки значат, и присвойте их переменным с осмысленным именем, например так:
function someFunct() { $orderId = 23; $selectedProductName = 'superComputer'; $this->order->set($orderId); $this->order->addProduct($selectedProductName); $this->shoppingList->add($selectedProductName); }
Кто-то может сказать что мы создаем ненужные переменные, но производительность пострадает незначительно. Читаемость кода всегда в приоритете. Запомните: не зацикливайтесь на производительности пока не сможете сказать зачем она вам нужна.
12 — Не борщите с переменными
С переменными легко переборщить, но помните что они хранятся в памяти. Для каждой созданной переменной, необходимо пространство в памяти компьютера, для хранения ее значения. Посмотрите на этот код:
public function get_posts() { $query = $this->db->get('posts'); $result = $query->result(); return $result; }
Переменная $result
здесь совсем ни к чему. Что и показывает следующий фрагмент:
public function get_posts() { $query = $this->db->get('posts'); return $query->result(); }
Разница не велика, но мы смолги улучшить этот простой пример. Мы обошлись переменной $query обращающейся к базе данных, в то время как $result использовалась больше для логики.
Общие рекомендации про программированию
13 — Разумно называйте свои переменные
Дни когда переменные назывались x
, y
, z
прошли (только если дело не касается систем координат конечно). Переменные представляют важную часть логики программы. Не хотите печатать длинное имя? Раздобудьте IDE по-лучше. Современные IDE имеют функцию автозавершения длинных имен.
Если вы будете постоянно писать код в течении шести месяцев. Вспомните ли вы что скрывает в себе переменная
$sut
, которую вы когда-то написали? Скорее всего нет: будьте описательны. Все короткое придает коду запашок.
14 — Методы описывающие действие
Ошибки случаются; важно учиться на них.
Именуйте методы используя глаголы обозначающие их действие. Основная концепция заключается в оппозитной схеме именования переменных. Используйте короткие, но описательные, имена для часто используемых методов (читай публичных методов), и наоборот, длинные и более детальные имена для редко используемых (приватных и защищенных методов). Это сделает чтение вашего кода подобно хорошей прозе.
Кроме того, не допускайте применения любого другого языка, отличного от Английского. Порой раздражает видеть функции с именами вроде 做些什麼() или четоделать() в вашем проекте. Это может сделать непонятным для других программистов назначение ваших методов Сегодня Английский это стандарт де-факто в программировании. Используйте только его, особенно если вы работает в команде.
15 — Рекомендации по структуре
И наконец что касается структуры кода. Читаемость и понятность кода также важна как и все о чем мы сегодня говорили. Две рекомендации:
- Используйте отступы в 2 или 4 пробела. Немного больше, например 8 пробелов, это слишком много и сделает ваш код сложным для чтения.
- Установите разумную ширину и придерживайтесь ее. 40 символов в строке? Нет, мы уже не в 70х; установите ширину в 120 знаков, поставьте отметку на экране, и заставьте себя или вашу IDE соблюдать этот лимит. 120 знаков прекрасная ширина, не заставляющая скроллить.
Заключение.
«Я никогда не делал глупых ошибок программирования»
Никто, нигде.
Ошибки случаются; важно учиться на них. Мы в Nettuts+ делали, и будем продолжать делать ошибки. Надеемся что вы научитесь на наших ошибках и постараетесь избегать их в будущем. Хотя, честно говоря, лучший способ научиться, это допустить собственные ошибки!
Спасибо за чтение!
Всех этих ошибок можно избежать, если руки растут из нужного места. Специалист, работающий в этой отрасли, поможет сделать так, чтобы было всё безупречно. Вывод: не стоит экономить на программировании