Способы сокращения JavaScript кода (продолжение)
Как и обещал, представляю Вам продолжение статьи «Способы сокращения JavaScript кода».
Быстрый способ преобразования «DOMNodeList» в «Array»
Итак, чем нас не устраивает «DOMNodeList»? Объект такого типа хоть и представляет из себя нумерованный массив, но не имеет методов, присущих объекту «Array». Например, в полученную коллекцию DOM-элементов мы хотим добавить еще несколько узлов, но удобного метода «push» у «DOMNodeList» нет, потому что это не «Array».
var list = document.body.childNodes;
alert(typeof list.push);
В результате выполнения этого кода, будет выведено сообщение «undefined». Преобразовать «list» в массив можно простым перебором элементов.
var list = document.body.childNodes,
length = list.length, array = [], i;
for(i = 0; i < length; array.push(list[i++]));
alert(typeof array.push);
Теперь выводится сообщение «function», мы успешно преобразовали «DOMNodeList» в «Array». Казалось бы, если нам потребуется такое преобразование выполнять в коде несколько раз, запишем все это в функцию и будем пользоваться, но есть еще более удобный и короткий способ. В JavaScript объект «Array» имеет метод «slice», который используется для выделения части массива. Так как элементы структуры «DOMNodeList» тоже представляют собой нумерованный список, то метод «slice» успешно преобразует «DOMNodeList» в «Array».
Оказалось, что этот пример не работает в IE. Если Вы знаете способ, как обойти ошибку, пожалуйста, напишите об этом в комментариях.
var list = document.body.childNodes, array = [];
array = array.slice.call(list);
alert(typeof array.push);
Снова «alert(typeof array.push);» выдает сообщение «function». Теперь запишем преобразование в самом кратком виде:
var array = [].slice.call(document.body.childNodes);
В итоге даже не нужно будет создавать отдельной функции, преобразующей «DOMNodeList» в «Array», итак все коротко и красиво.
Конструкция «for(…in…)» работает не только с ассоциативными массивами
Многие программисты, пришедшие в JavaScript из PHP, очень любят использовать везде ассоциативные массивы (хэши) и аналог «foreach», представленный в JavaScript конструкцией «for(…in…)», даже там, где это совершенно не нужно. Конструкция «for(…in…)» работает с любым объектом, в том числе и с «Array».
Например, нам нужно выполнить функцию, для некоторого набора элементов. Нас не интересует их количество и названия (ключи).
var key, list = {
x: 'xxx',
y: 'yyy',
z: 'zzz'
}
for(key in list) alert(key);
Ключи «x», «y» и «z» вообще нигде не участвуют в коде. Давайте перепишем код с использованием «Array».
var key, list = ['xxx', 'yyy', 'zzz'];
for(key in list) alert(key);
Запись стала немного короче, за счет удаления ключей ассоциативного массива и разделителя «:» (двоеточие). Таким образом, можно перебрать еще и все символы в строке. Главное не забывайте, что если в «prototype» этого объекта находятся пользовательские методы, то переменная «key» будет получать ссылки и на них тоже. Чтобы этого избежать, необходимо ввести проверку на принадлежность метода/атрибута текущему объекту.
var key, list = ['xxx', 'yyy', 'zzz'];
for(key in list) if(list.hasOwnProperty(key)) alert(key);
Чтобы не делать подобных вещей, в этих случаях лучше использовать обычный перебор по номеру элемента.
var i, list = ['xxx', 'yyy', 'zzz'], length = list.length;
for(i = 0; i < length; alert(list[i++]));
В таком виде в цикле всегда перебираются только нужные нам элементы. Использование «for(…in…)» не только для ассоциативных массивов в некоторых случаях помогает сократить код, но нужно быть предельно внимательным, используя эту конструкцию. В общем, забудьте этот пример, зря я его, наверное, написал
Сокращаем и упорядочиваем названия переменных и функций
Обычно, если в проекте уже не используется какой-либо JavaScript framework, то программист пишет свой набор функций, которые часто будет применять.
function newElement(tag) {
return document.createElement(tag);
}
function newText(str) {
return document.createTextNode(str);
}
function getElement(id) {
return document.getElementById(id);
}
function getElements(tag) {
return document.getElementsByTagName(tag);
}
function addEvent(obj, type, listener) {
if(obj.addEventListener)
obj.addEventListener(type, listener, false);
else if(obj.attachEvent)
obj.attachEvent('on' + type, listener);
}
В большинстве случаев, эти функции так и остаются лежать в глобальном пространстве имен, поэтому для них придумывают достаточно длинные названия, чтобы вдруг не пересекались с уже имеющимися именами переменных. Да еще и IE портит жизнь, добавляя идентификаторы DOM-узлов, как переменные в глобальном пространстве имен. Давайте как-нибудь получше организуем наш набор функций.
var dom = {
new: {
tag: function(tag) {
return document.createElement(tag);
},
text: function(str) {
return document.createTextNode(str);
}
},
get: {
id: function(id) {
return document.getElementById(id);
},
tag: function(tag) {
return document.getElementsByTagName(tag);
}
},
event: {
add: function(obj, type, listener) {
if(obj.addEventListener)
obj.addEventListener(type, listener, false);
else if(obj.attachEvent)
obj.attachEvent('on' + type, listener);
}
}
}
Кода стало немного больше, но теперь внутри объекта «dom» мы можем использовать любые короткие и понятные названия.
// было
var list = getElements('div');
// стало
var list = dom.get.tag('div');
// было
var node = newElement('span');
// стало
var node = dom.new.tag('span');
Помоему, стало все логичнее и удобнее для восприятия. Вы тоже так считаете?
Используем логичные и понятные названия функций и переменных
Я предпочитаю практически не использовать комментарии в JavaScript коде, а чтобы сохранить читаемость, всегда придумываю короткие, но в тоже время понятные и логичные названия функциям и переменным, а так же применяю структурирование, как это показано в предыдущем примере. От комментариев приходится отказываться из-за критичности размера js-файла.
Всегда ли нужны «true» и «false»?
В условных конструкциях языка JavaScript могут использоваться не только значения «true» и «false». В качестве ложного значения могут приниматься: «0», «undefined», «null». За истинное значение может использоваться, например, факт наличия объекта или любое число, отличное от нуля… Поэтому не усложняйте условные конструкции дополнительными логическими выражениями.
if(typeof document.getElementById('test') != 'undefined')
alert('exist');
else alert('not find');
// или
if(!!document.getElementById('test')) alert('exist');
else alert('not find');
// тоже самое
if(document.getElementById('test')) alert('exist');
else alert('not find');
// или
alert(document.getElementById('test') ? 'exist' : 'not find');
Или вот еще яркий пример, при определении длины массивов и строк:
var array = ['a', 'b', 'c'];
if(array.length != 0) {
// что-то делаем c array
}
// или
if(array.length > 0) {
// что-то делаем c array
}
//тоже самое
if(array.length) {
// что-то делаем c array
}
«copy-paste» для ленивых
Никогда не копируйте чужие коды. Не поленитесь и напишите то же самое самостоятельно. Уверен, что Вы найдете способ написать код лучше, чем это сделано в рассматриваемом Вами примере.
Спонсор поста: Агентство «Web++» — продвижение и создание сайтов в Волгограде.
Похожие темы
RSS-лента комментариев к этой статье | Обратная ссылка (trackback link)

Вы уверены насчет
slice?Да, действительно, увлекся сокращением, пропустил «
call» или «apply». Только теперь заметил, что не работает в IE, попробую найти решение… Странно вообще, с объектом «arguments», который тоже не является массивом, код работает в IE, а вот с «DOMNodeList» — нет.Делаю обычно так
на счет
for( .. in ..)вы уверены что оба варианта вернут одно и тоже?В конструкции
for(var key in ['xxx','yyy','zzz'])key будет 0,1,2а в
for(var key in [x:'xxx',y:'yyy',z:'zzz']),будет x,y,zИ это я только начал смотреть.
Записи
и
практически одно и тоже, но в первом случае не создается пустой массив — это уже можно отнести к оптимизации… Но оба этих варианта не работают в «Internet Explorer».
Про массивы, да я знаю, что при использовании конструкции «
for(key in array)» значениями «key» являются ключи массива, поставьте «array[key]», чтобы использовать значения массива.Кстати, Ваш пример «
for(var key in [x:'xxx',y:'yyy',z:'zzz'])» не корректный, таким образом массивы записывать нельзя. Правильно будет «{x: 'xxx', y: 'yyy', z: 'zzz'}», но это уже ассоциативный массив…не уверен, что стоит полностью отказываться от комментариев. хотя, конечно у себя свожу их к минимуму — ограничиваюсь кратким описанием функции/объекта (не более 3-4 слов) капсом перед определением