Блогът на Гонзо

Self-initialising Module Pattern

Доста време не съм писал в блога, предишната публикация е от преди повече от две години. Смятам обаче да променя това и сега ще се опитам да ви покажа до какъв design pattern достигнах, работейки по един проект.

Въпросният проект го написахме на чист JavaScript без да използваме jQuery или друга подобна библиотека, което само по себе си беше доста забавно. В началото кода ми беше доста разхвърлян, но постепенно обособих някои неща в собствени модули. Следващото нещо беше да намаля заявките към DOM и да „кеширам“ намерените елементи в локални проемнливи. За да ви покажа по-ясно за какво става дума ще започна със следния пример:

var messageBox = (function(){

  var box = message = buttons = success = cancel = null,
       self = this;

  this.init = function(){

    self.box = document.getElementById('message-box');
    self.message = self.box.getElementsByTagName('p')[0];
    self.buttons = self.box.getElementsByTagName('button');

    self.box.classList.add('hidden');

    for(var i = 0, bl = buttons.length; i < bl; i++){
      buttons[i].onclick = function(){
        self.box.classList.ьаа('hidden');
        if(typeof self[this.dataset.action]  == 'function'){
          self[this.dataset.action]();
        }
      }
    }

  };

  this.show = function(message, type, success, cancel){
    if (type == 'none') {
      self.box.classList.add('hidden');
      return;
    }
    else if(type == undefined || type == '') {
      type = 'ok-only';
    }
    self.box.className = type;
    self.message.innerHTML = message;
    self.success = success;
    self.cancel = cancel;
  };

  return { init: init, show: show }

})();

domready(messageBox.init);

Използвайки Revealing Module pattern сме направили един хубав обект, но за да работят нещата трябва когато браузъра приготви DOM-а да извикаме неговия init метод. А когато искаме да покажем съобщение, трябва да викаме малко тегавото messageBox.show(), въпреки че модула няма други полезни методи. И когато подобните модули станат повече от един това викане на разни init методи почва да става досадно. А не може ли модулите сами да се инициализират? Ми може:

var messageBox = (function(){

  var box = message = buttons = success = cancel = null,
       self = this;

  domready(function(){

    self.box = document.getElementById('message-box');
    self.message = self.box.getElementsByTagName('p')[0];
    self.buttons = self.box.getElementsByTagName('button');

    self.box.classList.add('hidden');

    for(var i = 0, bl = buttons.length; i < bl; i++){
      buttons[i].onclick = function(){
        self.box.classList.add('hidden');
        if(typeof self[this.dataset.action]  == 'function'){
          self[this.dataset.action]();
        }
      }
    }

  });

  this.show = function(message, type, success, cancel){
    if (type == 'none') {
      self.box.classList.add('hidden');
      return;
    }
    else if(type == undefined || type == '') {
      type = 'ok-only';
    }
    self.box.className = type;
    self.message.innerHTML = message;
    self.success = success;
    self.cancel = cancel;
  };

  return this.show;

})();

Разликата тук е, че модула сам се грижи да се инициализира когато DOM-а е готов. Освен това в конкретния случай това позволява и модула да изложи на показ само една функция, което прави използването по-лесно.

И преди да сте попитали защо да не използваме една проста функция, която да върши всичко – намирането или създаването на елементите, обслужването на събитията и т.н. (често срещан подход при използване на jQuery) – ами защото е скъпо. Работата с DOM е вероятно най-тежкото нещо, което JavaScript ще върши, и ако можем да си спестим повтарянето на едни и същи тежки операции, потребителите ще ни благодарят.

Етикети:

Comments (0)

Leave a comment

XHTML: Allowed tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>