Объектный подход к созданию Javascript-плагинов

Пост будет полезен тем, кто хочет использовать полноценные объекты в Javascript.

У каждого профессионального программиста в течении долгих лет практики формируется свой подход к каждому языку.
В начале изучения JavaScript я делал так:

function Test() {... some code ...}


..., затем научился создавать объекты и стал делать так:

var Test = {
  var1: 'someText',
  func1: function() {... some code ...}
}


Потом было еще множество неверных подходов к Javascript'у, прочитанных где-то на форумах и блогах.

В конце концов у меня сформировался собственный подход к Javascript'у, он подразумевает простое создание полноценных(ну почти) объектов, имеющих [приватные | доступные] [обычные | статические] свойства и методы.

В качестве примера привожу собственный код js-объекта для встраивания Flash:

(названия некоторых переменных изменены!)
$plugin = function(params) {
  var plugin = {
    /* PUBLIC VARS */
    isReady: false,
    id: 'VP_' + $plugin.count++,
    /* PRIVATE VARS */
    cfg: params,
    handlers: {
      "ready": [
        function(plugin){
          plugin.isReady = true;
        }
      ]
    },
    /* INIT */
    init: function() {
      this.cfg.id = this.id;
      this.fv = (this.getFlashVars(this.cfg));
      this.html = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" id="' + this.id + '" width="100%" height="100%" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" align="top"><param name="wmode" value="opaque"></param>'
           + '<param name="movie" value="' + this.cfg.url + '"></param>'
           + '/>'
           + '/>'
           + '/>'
           + '/>'
           + '/>'
           + '/>'
           + '/>'
           + '<param name="flashvars" value="' + this.fv + '"></param>'
           + '<embed name="' + this.id + '" src="' + this.cfg.url + '" flashvars="' + this.fv + '" width="100%" height="100%" align="top" play="true" loop="false" quality="high" allowScriptAccess="sameDomain" allowFullscreen="true" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"></embed>'
           + '';
      document.write(this.html);
      this.embed = $plugin.getSWF(this.id);
      $plugin.embeds[this.id] = this;
        /* Это очень важный этап: возвращаю только что созданный объект plugin */
      return this;
    },
    /* PRIVATE METHODS */
    getFlashVars: function(cfg) {
      var fv = "";
      for (var i in cfg) {
        var v = cfg[i];
        if (typeof v == «object») {
          fv += i + "=" + escape(this.encodeJSON(v)) + "&";
        } else {
          fv += i + "=" + escape(v) + "&";
        }
      }
      return fv.substring(0, fv.length — 1);
    },
    encodeJSON: function(s) {
      var r = "";
      if (s.constructor == Array) {
        r += "[";
        for (var i in s) {
          r += this.encodeJSON(s[i]) + ",";
        }
        r = r.substring(0, r.length — 1) + "]";
      } else if (typeof s == «object») {
        r += "{";
        for (var i in s) {
          r += '"' + i + '":' + this.encodeJSON(s[i]) + ",";
        }
        r = r.substring(0, r.length — 1) + "}";
      } else if (typeof s == «string») {
        r = '"' + s + '"';
      } else {
        r = s;
      }
      return r;
    },
    /* PUBLIC METHODS */
    changeView: function(data) {
      this.embed.changeView(data);
    },
    addEventListener: function(evName, handler) {
      if (evName == «ready» && this.isReady) {
        handler(this);
      } else {
        if (!this.handlers[evName]) {
          this.handlers[evName] = [];
        }
        this.handlers[evName].push(handler);
      }
    },
    dispatchEvent: function(evName) {
      if (this.handlers[evName]) {
        for (var i = 0; i < this.handlers[evName].length; i++) {
          this.handlers[evName][i](this);
        }
      }
    }
  };
    /* Как уже было сказано выше, в результате выдаем только что созданный объект plugin */
  return plugin.init();
};

/* PUBLIC STATIC VARS */
$plugin.count = 0;
$plugin.embeds = [];

/* PRIVATE STATIC METHODS */
$plugin.isReady = function() {
  return true;
};
$plugin.dispatchReady = function(id) {
  $plugin.embeds[id].dispatchEvent(«ready»);
};

/* PUBLIC STATIC METHODS */
$plugin.getSWF = function(id) {
  if (navigator.appName.indexOf(«Microsoft») != -1) {
    return window[id];
  } else {
    return document[id];
  }
};



Кто-то скажет, что можно было бы еще спрятать приватные методы и свойства: Вы правы! Стоит заключить приватные статичные свойства и методы, например, в $plugin.privates, а не статичные в plugin.privates. Можно было бы еще предусмотреть метод plugin.removeEventListener… Но этот пример иллюстрирует вовсе не то, как лучше встраивать Flash. Он иллюстрирует лучший подход к Javascript'у.

Чем этот подход лучше? Вот этим:

— Используя данный подход, вы избавляете себя от ненужного написания лишнего кода, который обычно требуется для создания объектов Javascript другими способами, как например вот этими: Дурацкий метод создания js-объектов

— Получаете гибкие и практически полноценные объекты, которые вы можете использовать например вот так:

var videoPlayer = $plugin({
    /* SWF FILE */
    'url': '/swf/Blue.swf',

    /* APPEARANCE */
    'skin': '/plugin/content/Blue.xml',
    'showBackButton': true, /* true or false */
    'showMuteButton': true, /* true or false */
    
    /* BASE SETTINGS */
    'autoPlay': false, /* true or false */
    'volume': 0, /* min = 0, med=0.5, max = 1.0 */
    
    /* STREAMING & PLAYLIST */
    'streaming': 'http', /* 'none', 'http', 'rtmp' */
    'playlist': [
      {
        'videoUrl': '/videos/flvPHPStreaming?file=Extremists.flv&start=${start}&bw=mid',
        'imageUrl': '/videos/preview-img.png'
      }
    ]
    
  });
  // Доступ к методам
  videoPlayer.addEventListener("ready", function(plugin){
      videoPlayer.changeView(data);
  });
  // Доступ к свойствам
  alert(videoPlayer.isReady);



В этом примере мы получим локальный объект videoPlayer с доступными методами changeView, addEventListener и dispatchEvent. У вас также будет глобальный объект $plugin со статичным методом $plugin.getSWF и свойствами $plugin.count и $plugin.embeds.

— В целом, если правильно использовать этот подход, код Javascript будет лучше организован и интуитивно-понятен.


0 комментариев

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.