czwartek, 18 października 2012

[HTML|JS|CSS] JavaScript Patterns: Tworzenie obiektów

Tym razem kilka wzorców projektowych charakterystycznych dla języka JavaScript, które przydają się przy tworzeniu obiektów. Z jakimi podstawowymi problemami spotyka się programista w tym języku ? Przede wszystkim jest to brak klas i przestrzeni nazw. Poniżej użyteczne wzorce.

  • Przestrzeń nazw

Spore zapotrzebowanie na zmienne globalne powoduje zaśmiecanie obiektu okna. Aby temu zapobiec tworzy się jeden globalny obiekt będący odpowiednikiem modułu reprezentującego pewne właściwości.

var mymodule = mymodule || {};
mymodule.length = 3;
mymodule.maxusers = 15;
mymodule.config = {};
mymodule.config.initialtext = "hello world";

  • Prywatne składowe

Aby uzyskać efekt prywatnych składowych obiektu można skorzystać z konstrukcji closure.

function Person(name){
 var myname = name;
 this.getName = function(){
  return myname;
 };
 this.setName = function(str){
  myname = str;
 };
}

var sb = new Person("John");
console.log(sb.myname);
console.log(sb.getName());
sb.setName("Joe");
console.log(sb.getName());

  • Wzorzec modułu

Połączenie kilku mniejszych wzorców, mające na celu utworzenie obiektu będącego modułem z prywatnymi zmiennymi, metodami itd.

var mymodule = {};
mymodule.array = {};
mymodule.array.utils = function(){
 //private members
 var logged = 0;
 var logger = function(i,e){
  logged++;
  console.log("Index:" + i + ", element: " + e);
 };
 //public members
 var totalLogged = function(){
  return logged;
 };
 var printArray = function(array){
  for (var i = array.length - 1; i >= 0; i--) {
   logger(i,array[i]);
  }
 };
 //public API
 return{
  print : printArray,
  total : totalLogged
 };
}();

var myarray = ['one','two','three'];

mymodule.array.utils.print(myarray);
console.log(mymodule.array.utils.total());

  • Sandbox

Ulepszona wersja wzorca przestrzeni nazw. Ponieważ każda funkcja jest obiektem, możemy w niej enkapsulować serwisy i przez samą funkcję się do nich odwoływać oraz zwracać je za pomocą callbacku.

function Sandbox(){
 var args = Array.prototype.slice.call(arguments),
 callback = args.pop(),
 modules = (args[0] && typeof args[0] === "string") ? args : args[0],
 i;

 if(! (this instanceof Sandbox)){
  return new Sandbox(modules, callback);
 }

 for(i = 0; i < modules.length; i += 1){
  Sandbox.modules[modules[i]](this);
 }

 return callback(this);
}

Sandbox.modules = {};
Sandbox.modules.vector = function(box) {
 box.sum = function(v){
  var sum = 0;
  for (var i = v.length - 1; i >= 0; i--) {
   sum += v[i];
  }
  return sum;
 };
 box.normalize = function(v,sumfun){
  var sum = sumfun(v);
  var arr = [];
  for (var i = v.length - 1; i >= 0; i--) {
   arr.push(v[i]/sum);
  }
  console.log(arr);
 };
};

Sandbox('vector', function(box){
 var a = [1,2,3,4];
 console.dir(box.sum(a));
 box.normalize(a,box.sum);
});

  • Statyczne pola

Aby uzyskać konstrukcję składniową statycznego pola, znaną z języków obiektowych typu C++, należy pamiętać o tym, że każda funkcja jest obiektem, do którego można dynamicznie przypisywać właściwości.

function Computer(){
 Computer.instances++;
 return {
  ram : 4096,
  hdd : 1024
 };
}

Computer.instances = 0;

var computers = [new Computer(), new Computer()];
console.log(Computer.instances);

  • Chaining pattern


Jest to wzorzec umożliwiający wywoływanie wielu funkcji w łańcuchu, co poprawia czytelność kodu i zmniejsza jego ilość, kosztem utrudnień w testowaniu.
var number = {
 value : 0,
 add : function(x){
  this.value += x;
  return this;
 },
 multiply : function(x){
  this.value *= x;
  return this;
 },
 print : function(){
  return this.value;
 }
};

console.log(number.add(10).multiply(12).print());

Brak komentarzy:

Prześlij komentarz