var mysite = {
    'url': "http://www.ajaxweb20.net",
    'author': "Giuseppe Raso",
    'xhtmlValid': true,
    'cssValid': true
}
Home > Blog

Posts Tagged ‘classi’

Javascript: Usare apply per passare vari argomenti a un costruttore.

Lunedì, Marzo 31st, 2008

Apply come già sicuramente saprete permette di passare degli argomenti ad una funzione sotto forma di array; tra l’altro lo stesso apply permette di specificare l’oggetto contesto della funzione, in altra parole l’oggetto che si potrà richiamare mediante l’operatore this.

function fn() {
  for(var i = 0, l = arguments.length; i!=l; i++) {
    this[i] = arguments[i] + "xyz";
  }
}

fn.apply([], ["a", "b", "c"]);

Qualcuno si sarà chiesto se sia possibile usare apply con i costruttori, qualcuno magari avrà provato anche a scrivere il seguente codice ricevendo in cambio l’errore “xxx is not a constructor”:

function miaClasse() {
  this.method = function() {
  }
  this.str = arguments[0] || ;
}

new miaClasse.apply(null, ["str"]) //Attenzione, questo codice NON funziona!!!

Fortunatamente non è molto difficile arrivare a una prima soluzione:

miaClasse.apply(new miaClasse, ["a"]); //Questo invece funziona!!!

Resta ancora un problema: il codice all’interno della classe miaClasse viene eseguito inutilmente due volte, e tra l’altro a causa dell’assenza di argomenti non è detto che non possa causare un errore.

La soluzione è quella di creare un’altra classe che erediti le proprietà dalla classe originaria e usare l’oggetto creato con questa classe:

function klass() {
  miaClasse.apply(new this, arguments)
}

function intermediate() {
}

intermediate.prototype = miaClasse.prototype;

klass.prototype = new intermediate;

//Esempio

klass.apply(null, [/*arguments…*/])

Notare che la proprietà constructor non viene corretta ( solitamente lo si fa in ogni ereditarietà ) proprio perchè potrebbe essere utile considerare l’oggetto restituito da miaClasse come se fosse un’istanza di miaClasse invece che di klass.

Infine come buona norma astrattizziamo il codice e trasformiamolo in funzione, anzi, visto che ci siamo che ne dite di un prototipo con un bel lazy pattern? :D

Function.prototype.instance = function(args) {

  var this_ = this;
  function klass() {
    this_.apply(new this, arguments[0])
  }

  function intermediate() {
  }

  intermediate.prototype = miaClasse.prototype;

  klass.prototype = new intermediate;

  this_.instance = klass;

  this_.instance(args);

}

Enjoy :)

Workaround per usare __defineGetter__ e __defineSetter__ su elementi HTML

Venerdì, Marzo 28th, 2008

defineGetter e defineSetter sono due metodi dannatamente utili supportati al momento da Firefox, Opera 9.5, Safari 3 e Konqueror. Essi permettono di manipolare le proprietà dichiarando un setter ( una funzione che viene eseguita opgni volta che settiamo una proprietà ) o un getter ( una funzione che viene usata ogni volta che prendiamo una proprietà in modo da manipolare il valore ritornato ).

Teoricamente potremmo usarlo per simulare innerText su Firefox:

HTMLElement.prototype.__defineSetter__("innerText", function(value) { this.textContent = value; })

Purtroppo in Firefox 2 ( con la versione 3 il problema non sussiste ) non è possibile definire ne getter ne setter sugli elementi HTML :(
Si tratta di uno strano bug che fortunatamente ha un workaround molto semplice, ovvero quello di applicare il getter/setter alla classe Node:

Node.prototype.__defineSetter__("innerText", function(value) { this.textContent = value; })

L’unico svantaggio è che così facendo stiamo applicando il setter a tutti i tipi di nodi, compresi nodi testo, commento e persino documento!

Ma anche in questo caso la soluzione è alquanto semplice:

Node.prototype.__defineSetter__("innerText", function(value) {
  if(this.nodeType == 1)
    this.textContent = value;
  else
    this.innerText = value;
})

Semplicemente controlliamo che il nodo sia veramente un elemento HTML ( con nodeType uguale a 1 ): se è vero settiamo la proprietà textContent ( il rispettivo di innerText in IE ) altrimenti ci comportiamo come se il setter non esistesse, ovvero settando la proprietà innerText manualmente.

Volendo possiamo “standardizzare” questa operazione tramite una funzione ( Ah che belle le closures :D ):

HTMLElement.$defineSetter = function(prop, fn) {
  Node.prototype.__defineSetter__(prop, function(value) {
    this.nodeType == 1
      ? fn.call(this, value)
      : this[prop] = value;
  })
}

Con poche modifiche possiamo creare una funzione che crea un getter:

HTMLElement.$defineGetter = function(prop, fn) {
  Node.prototype.__defineGetter__(prop, function() {
    retun this.nodeType == 1)
      ? fn.call(this, value)
      : this[prop];
  })
}

Per altri snippet stay tuned!

Una guida completa sull’erediterietà in Javascript.

Mercoledì, Marzo 26th, 2008

Per chi sta iniziando adesso ad addentrarsi nei meandri di questo potente linguaggio di scripting, ma anche ai più esperti ( non si smette mai di imparare :) ) consiglio caldamente la lettura di questa guida ( in inglese ) sull’ereditarietà in Javascript.

Tra le guide inerenti l’argomento che abbia mai letto questa è senza ombra di dubbio la più completa, e tra l’altro riassume gli studi fatti recentemente dallo stesso Giammarchi e da altri javascripter di fama internazionale.

L’unico neo rilevante della guida è che forse la lettura potrebbe apparire alquanto oscura a chi ha poca o nulla dimestichezza con l’argomento…
Nel caso vi riconosciate in questa categoria vi consiglio caldamente di leggere anche questo vecchio post.