Ведро и не ядро

от автора

Что плохо на примере jq.

Рассмотрим на задаче и её реализации: Есть x элементов, по клику на элемент он должен поменять состояние. Кликов на элементе может быть, и чаще всего будет, не одни.

Вёрстка.
Элементов много — нахождение по классу.

<body> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> </body> 

// бесспорно ок.

JS.
Найти по классу, повесить клик, обработать клик, отмечен — снять, не отмечен — отметить

jQ
подключили jQ
Решение Задачи

$(function(){     $('.testDiv').on('click', function(){         var vedroCache = $(this);         if (vedroCache.hasClass('isActiveTestDiv')){             vedroCache.removeClass('isActiveTestDiv');         } else{             vedroCache.addClass('isActiveTestDiv');         }     }); }); 

JS
Вместо jq

//писать ≈2—3ч в с чаем и твиттером в выходные (function(u){     var J = {},         W = window,         D = document,         intCache;     W.J = J; //    search elements     if ('getElementsByClassName' in document){         J.$c = function(className, from){             return (from || D).getElementsByClassName(className);         }     } else{         J.$c = function(className, from){             var cache = (from || D).getElementsByTagName('*'),                 result = [],                 i = cache.length,                 j = -1;             for (; i-- ;){                 if (cache[i].className.indexOf(className) !== -1){                     result[j += 1](cache[i]);                 }             }             return result;         }     } //    events     if ('addEventListener' in W){         J.eventAdd = function(object, eventName, callback){             object.addEventListener(eventName, callback);         };         J.eventDel = function(object, eventName, callback){             object.removeEventListener(eventName, callback);         };     } else{         var ieFixEventsNameObjectsCallbacks = [],             ieFixEventsObjectsAndCallbacksLength = 0,             ieFixEventsHandlers = {},             fixEvent = function(e){                 e.preventDefault = function(){                     e.returnValue = false;                 };                 e.stopPropagation = function(){                     e.cancelBubble = true;                 };                 e.target= e.srcElement;                 return e;             },             ieAddFixEvent = function(object, eventName, callback){                 function fix(){                     callback.call(object, fixEvent(W.event));                 }                 intCache = ieFixEventsObjectsAndCallbacksLength;                 ieFixEventsNameObjectsCallbacks[ieFixEventsObjectsAndCallbacksLength] = eventName;                 ieFixEventsObjectsAndCallbacksLength += 1;                 intCache += ieFixEventsObjectsAndCallbacksLength;                 ieFixEventsNameObjectsCallbacks[ieFixEventsObjectsAndCallbacksLength] = callback;                 ieFixEventsObjectsAndCallbacksLength += 1;                 intCache += ieFixEventsObjectsAndCallbacksLength;                 ieFixEventsNameObjectsCallbacks[ieFixEventsObjectsAndCallbacksLength] = object;                 ieFixEventsObjectsAndCallbacksLength += 1;                 ieFixEventsHandlers[intCache] = fix;                 object.attachEvent('on' + eventName, fix);             },             ieRemoveFixEvent = function(object, eventName, callback){                 for (var i = ieFixEventsObjectsAndCallbacksLength; i-- ;){                     if ((ieFixEventsNameObjectsCallbacks[i] === object) && (ieFixEventsNameObjectsCallbacks[i - 1] === callback) && (ieFixEventsNameObjectsCallbacks[i - 2] === eventName)){                         ieFixEventsNameObjectsCallbacks[i] = ieFixEventsNameObjectsCallbacks[i - 1] = ieFixEventsNameObjectsCallbacks[i - 2] = u;                         i = i * 3 - 3;                         break;                     }                     i -= 2;                 }                 if (i !== -1){                     object.detachEvent('on' + eventName, ieFixEventsHandlers[i]);                     ieFixEventsHandlers[i] = u;                 }             };         J.eventAdd = function(object, eventName, callback, isNotNeedFix){             if (isNotNeedFix === true){                 object.attachEvent('on' + eventName, callback);             } else{                 ieAddFixEvent(object, eventName, callback);             }         };         J.eventDel = function(object, eventName, callback, isNotNeedFix){             if (isNotNeedFix === true){                 object.detachEvent('on' + eventName, callback);             } else{                 ieRemoveFixEvent(object, eventName, callback);             }         };     } //    classes     J.classHas = function(object, className){         return object.className.indexOf(className) !== -1; //да без регулярок*     };     J.classAdd = function(object, className){         if (!J.classHas(object, className)){             object.className += ' ' + className;         }     };     J.classDel = function(object, className){         if (J.classHas(object, className)){             object.className = object.className.replace(className, '');  //да без регулярок*         }     };     //*проектирование уникальных классов для DOM элементов вьюшек — простая стандартизируемая (автоматизируемая) задача! //    fast bad ready     J.ready = function(callback){         var callbacks = [callback];         function ready(){             var iMax = callbacks.length,                 i = 0;             J.eventDel(D, 'DOMContentLoaded', ready);             J.eventDel(W, 'load', ready, true);             for (;i < iMax; i += 1){                 callbacks[i].call(J);             }             ready = callbacks = null;             J.ready = function(callback){                 callback.call(J);             }         }         if ('addEventListener' in W){             J.eventAdd(D, 'DOMContentLoaded', ready);         }         J.eventAdd(W, 'load', ready, true);         J.ready = function(callback){             callbacks.push(callback);         }     }; }()); 

Решение задачи

J.ready(function(){     var J = this,         elems = J.$c('testDiv'),         i = elems.length;     function clickListener(){         J[J.classHas(this, 'isActiveTestDiv') ? 'classDel' : 'classAdd'](this, 'isActiveTestDiv');     }     for (;i--;){         J.eventAdd(elems[i], 'click', clickListener);     } }); 

До объяснений проблем ведра хотелось бы заметмть, инит решения при 350 дивах и следующей эмуляции console.time

if (!('console' in window) || !('time' in console)){     (function(w){         var times = {},             C;         if (!('console' in w)){             w.console = C =  {};             C.log = function(data){                 alert(data);             }         } else{             C = w.console;         }         C.time = function(name){             times[name] = new  Date().getTime();         };         C.timeEnd = function(name){             if (name in times){                 return new Date().getTime() - times[name];             }         };     }(window)); } 

на машинке
masinka
и в фоксе 18.0.1
jQ ≈16ms
J ≈2ms

А в чём разница?
По мимо кучи кода, основная разница в подходах.

Подход «ведро»
Концепт — осознать, применить, т.е.

$(/*всё что угодно*/)./*сделай с ним что то*/

Мы можем менять jq на любые другие штуки, но концепт остаётся один и тот же.

Есть функция готовая ко всему (ведро), которая возвращает результат своей обработки в своей оболочке с набором действий.

В следствии чего

//мы должны надеятся на то, что ведро нас поймёт $('.testDiv').on('click', function(){         var vedroCache = $(this); // и во многих элементарных случая мы должны обрабатывать через ведро каждый раз         if (vedroCache.hasClass('isActiveTestDiv')){             vedroCache.removeClass('isActiveTestDiv');         } else{             vedroCache.addClass('isActiveTestDiv');         }     });     console.log(console.timeEnd('divs')); 

Подход «не ведро» (набор решений)

/*название решения*/(/*параметры задачи :)*/)

Считаю правильным, если решение валится от неправильных параметров.

J.ready(function(){     var J = this,         elems = J.$c('testDiv'), //найти по классу         i = elems.length;     function clickListener(){         J[J.classHas(this, 'isActiveTestDiv') ? 'classDel' : 'classAdd'](this, 'isActiveTestDiv'); //нет поставить, есть убрать     }     for (;i--;){         J.eventAdd(elems[i], 'click', clickListener); //повесить событие на конкретный элемент     } }); 

Развивать тему по поводу контроля конкретных решений можно очень долго.
Вывод следующий: нужно максимально понимать и контролировать то что у вас происходит, не отдавая всё на откуп общепринятого ведра.

Результаты

ссылка на оригинал статьи http://habrahabr.ru/post/166877/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *