Diferència entre revisions de la pàgina «NF1 - Estructures definides pel Programador - Objectes»

De wikiserver
Dreceres ràpides: navegació, cerca
(Es crea la pàgina amb «= Objectes = == Instanciació d'objectes == La forma més sencilla de crear un nou objecte és amb una intrucció com aquesta : <pre> var o = {}; </pre> Això crea u…».)
 
Línia 5: Línia 5:
 
La forma més sencilla de crear un nou objecte és amb una intrucció com aquesta :
 
La forma més sencilla de crear un nou objecte és amb una intrucció com aquesta :
 
<pre>
 
<pre>
 
+
var obj1 = new Object();
var o = {};
+
var obj2 = {};
 
 
 
</pre>
 
</pre>
  
Línia 16: Línia 15:
 
o.feina = "contable";
 
o.feina = "contable";
 
o.antiguitat = 11;
 
o.antiguitat = 11;
 +
</pre>
 +
 +
Per eliminar una propietat podem utilitzar l'operador ''delete'':
 +
<pre>
 +
var obj1 = new Object()
 +
alert(obj1.nombre)  // undefined
 +
 +
obj1.nombre = "mundo"
 +
alert(obj1.nombre)  // "mundo"
 +
 +
delete obj1.nombre
 +
 +
alert(obj1.nombre)  // undefined otra vez
 +
</pre>
 +
 +
Per afegir un mètode podem fer:
 +
<pre>
 +
var obj1 = new Object();
 +
obj1.nombre = "mundo";
 +
obj1.saluda = function() { alert("hola "+this.nombre) };
 +
obj1.saluda();
 +
</pre>
 +
 +
També podem construir objectes de manera literal:
 +
<pre>
 +
var obj1 = {nombre:"mundo",
 +
            saluda: function() { alert("hola "+this.nombre) }
 +
};
 +
obj1.saluda();
 +
</pre>
 +
 +
I podem accedir als mètodes i a les propietats de diferents maneres:
 +
<pre>
 +
var obj1 = new Object();
 +
obj1.nombre = "mundo";
 +
obj1.saluda = function() { alert("hola "+this.nombre) };
 +
 +
alert("hola " + obj1.nombre);      // Acceso normal
 +
alert("hola " + obj1[ "nombre" ]);  // Acceso indexado con un literal
 +
var prop = "nombre";
 +
alert("hola " + obj1[ prop ]);      // Acceso indexado con una variable
 +
 +
obj1.saluda();        // Invocación normal
 +
obj1[ "saluda" ]();    // Acceso indexado con un literal
 +
var func = "saluda";
 +
obj1[ func ]();        // Acceso indexado con una variable
 +
</pre>
 +
 +
'''Mètodes privats'''
 +
Aquesta part ja s'ha vist en el capitol de les funcions, però no està de més tornar a fer una ullada:
 +
<pre>
 +
var Saludator = function(nom) {
 +
this.nombre = nom
 +
this.saluda = function() {
 +
alert("hola "+plural(this.nombre))
 +
}
 +
function plural(n) {
 +
return n + "s"
 +
}
 +
}
 +
var obj1 = new Saludator("mundo")
 +
obj1.saluda()
 +
// obj1.plural()  // fallaría porque plural() es privado
 
</pre>
 
</pre>
  
 
Els que venim d'un entorn orientat a objectes clàssic trobaran a faltar la encapsulació i la estructuració que implica el concepte de constructor de classe.
 
Els que venim d'un entorn orientat a objectes clàssic trobaran a faltar la encapsulació i la estructuració que implica el concepte de constructor de classe.
 +
Javascript proporciona aquest mecanisme però d'una manera molt diferent. En Javascript totes les funcions i els objectes tenen una propietat anomenada ''prototype'' que fa referència a un objecte buit de forma inicial. Aquest objecte buit es crea utilitzant la paraula ''new''.
 +
 +
=== Prototips i Herència  ===
 +
 +
Analitzarem l'us de la paraula ''new'' a una funció i veurem com la propietat ''prototype'' proporciona propietats per a la nova instància.
 +
 +
<pre>
 +
function Persona(){}
 +
Persona.prototype.caminar = function(){return true;};
 +
var pere = Persona();
 +
assert(pere === undefined, "No s'ha creat cap instancia de Persona");
 +
 +
var jaume = new Persona();
 +
assert(jaume && jaume.caminar && jaume.caminar(), "La instancia existeix i el mètode es pot cridar");
 +
</pre>
 +
 +
Podem veure en l'exemple anterior que pere te el valor ''undefined''. Aixó és així per que la funció Persona, si no es crida amb el constructor ''new'' no retorna cap valor.
 +
Veiem que és veritat, ja que quan el cridem amb el constructor ''new'' Jaume existeix i a més a més té un mètode anomenat ''caminar''.
 +
 +
==== Llavors, què és un prototip?? ====
 +
 +
Un prototype és un objecte del que altres objectes hereten propietats.Aquest objecte pot ser qualsevol objecte.
 +
L'herència basada en classes no existeix en Javascript, sinó que és herència basada en prototips. Això significa que no hi ha una jerarquia de classes real (amb la seva extends, accés super, etc.), sinó que cada ''classe'' té un objecte de referència (com si fos la seva classe pare) on consultar atributs i mètodes en cas que la nostra classe no els trobi. Podem intentar simular una jerarquia (ull, simular) usant aquests objectes de referència, anomenats prototips, amb una propietat especial que tenen totes les “classes” anomenada prototype. Aquesta propietat és asignable i la seva labor consisteix a guardar un objecte. Vegem-ho amb un exemple:
 +
 +
<pre>
 +
var Saludator = function(nom) {
 +
this.nombre = nom
 +
this.saluda = function() {
 +
alert("hola "+this.nombre)
 +
}
 +
}
 +
// Añade un objeto al prototipo
 +
Saludator.prototype = {
 +
apellido: "cruel",
 +
despide: function() {
 +
alert("adios "+this.nombre+" "+this.apellido)
 +
}
 +
}
 +
var obj1 = new Saludator("mundo")
 +
obj1.despide() // "adios mundo cruel"
 +
</pre>
 +
 +
 +
===== Quins objectes tenen prototip? =====
 +
 +
Tot objecte té un prototip per defecte. Com els prototips són objectes, tots ells tenen un prototip també. Solament hi ha una excepció: el prototip de l'objecte per defecte, al final de la cadena de prototips (Object).
 +
 +
Totes les classes tenen per defecte un objecte prototype buit, com si en crear-les es fes prototype = {}. Per aquesta raó, podem accedir a aquesta variable i assignar-li els atributs d'un en un. El següent exemple és completament equivalent a l'anterior:
 +
 +
<pre>
 +
var Saludator = function(nom) {
 +
this.nombre = nom
 +
}
 +
// Añade nuevas propiedades al prototipo
 +
Saludator.prototype.apellido = "cruel"
 +
Saludator.prototype.despide = function() {
 +
alert("adios "+this.nombre+" "+this.apellido)
 +
}
 +
 +
var obj1 = new Saludator("mundo")
 +
obj1.despide() // "adios mundo cruel"
 +
</pre>
 +
 +
 +
Ok, recapitulem… què deies que era un objecte?
 +
 +
Un objecte en Javascript és una col·lecció qualsevol de parells clau-valor. Si no és un valor primitiu (undefined, null, boolean, number o string) és un objecte.
 +
 +
==== Utilitzant Prototips ====
 +
 +
Estudia aquest codi:
 +
 +
<pre>
 +
function Persona(){
 +
this.parat = false;
 +
this.caminar = function(){return !this.parat;};
 +
}
 +
Persona.prototype.caminar = function(){return this.parat;};
 +
 +
var joan = new Persona();
 +
 +
assert(joan.caminar(), "La crida a caminar és la crida definida dintre de Persona i no al mètode del prototip");
 +
</pre>
 +
 +
Creieu que és cert l'assert?? Doncs sí. Això demostra que el membres de la instància creats dintre del constructor bloquejaran les propietats i els mètodes definits amb el mateix nom en el prototip.
 +
 +
==== Com abordar les referències als mètodes i propietats dels prototips ====
 +
 +
Amb els exemples vistos anteriorment, pots arribar a pensar que quan es crea un nou objecte es copien els valors i els mètodes del seu prototip, i si hi ha algún mètode o propietat que s'anomena igual, es sobreescriu el seu valor amb el valor que hi ha en el constructor de l'objecte.
 +
Si fos així, en el següent codi, el mètode caminar no es podria utilitzar :
 +
<pre>
 +
function Persona(){
 +
this.parat = true;
 +
}
 +
var joan = new Persona();
 +
Persona.prototype.caminar = function(){return this.parat;};
 +
 +
assert(joan.caminar(), "El mètode existeix, fins i tot quan la persona s'ha creat abans.");
 +
</pre>
 +
 +
Llavors, aixó demostra que no hi ha una copia de propietats si no molt més.
 +
El que succeeix es que les funcions i mètodes del prototip  s'adjunten a l'objecte construït i es consulta durant la conciliació de les referències de la propietat que es duen a terme en l'objecte. És a dir:
 +
 +
* 1. Quan es fa una referència de propietat a un objecte, es comprova a veure si existeix en el propi objecte, si existeix s'agafa el valor, si no...
 +
* 2. Es localitza el prototip associat al objecte i es comprova si existeix la propietat, Si existeix es retorna el valor, si no...
 +
* 3. El valor es ''undefined''
 +
 +
 +
<!--
 +
== Bibliografia ==
 +
 +
Secrets of the Javascript Ninja
 +
http://albertovilches.com/profundizando-en-javascript-parte-2-objetos-prototipos-herencia-y-namespaces
 +
-->

Revisió del 15:43, 18 nov 2013

Objectes

Instanciació d'objectes

La forma més sencilla de crear un nou objecte és amb una intrucció com aquesta :

var obj1 = new Object();
var obj2 = {};

Això crea un objecte nou, buit i que més tard podem ampliar amb propietats:

var o = {};
o.name = "Marta";
o.feina = "contable";
o.antiguitat = 11;

Per eliminar una propietat podem utilitzar l'operador delete:

var obj1 = new Object()
alert(obj1.nombre)   // undefined

obj1.nombre = "mundo"
alert(obj1.nombre)   // "mundo"

delete obj1.nombre

alert(obj1.nombre)   // undefined otra vez

Per afegir un mètode podem fer:

var obj1 = new Object();
obj1.nombre = "mundo";
obj1.saluda = function() { alert("hola "+this.nombre) };
obj1.saluda();

També podem construir objectes de manera literal:

var obj1 = {nombre:"mundo",
            saluda: function() { alert("hola "+this.nombre) }
};
obj1.saluda();

I podem accedir als mètodes i a les propietats de diferents maneres:

var obj1 = new Object();
obj1.nombre = "mundo";
obj1.saluda = function() { alert("hola "+this.nombre) };

alert("hola " + obj1.nombre);       // Acceso normal
alert("hola " + obj1[ "nombre" ]);  // Acceso indexado con un literal
var prop = "nombre";
alert("hola " + obj1[ prop ]);      // Acceso indexado con una variable

obj1.saluda();         // Invocación normal
obj1[ "saluda" ]();    // Acceso indexado con un literal
var func = "saluda";
obj1[ func ]();        // Acceso indexado con una variable

Mètodes privats Aquesta part ja s'ha vist en el capitol de les funcions, però no està de més tornar a fer una ullada:

var Saludator = function(nom) {
	this.nombre = nom
	this.saluda = function() {
		alert("hola "+plural(this.nombre))
	}
	function plural(n) {
		return n + "s"
	}
}
var obj1 = new Saludator("mundo")
obj1.saluda()
// obj1.plural()  // fallaría porque plural() es privado

Els que venim d'un entorn orientat a objectes clàssic trobaran a faltar la encapsulació i la estructuració que implica el concepte de constructor de classe. Javascript proporciona aquest mecanisme però d'una manera molt diferent. En Javascript totes les funcions i els objectes tenen una propietat anomenada prototype que fa referència a un objecte buit de forma inicial. Aquest objecte buit es crea utilitzant la paraula new.

Prototips i Herència

Analitzarem l'us de la paraula new a una funció i veurem com la propietat prototype proporciona propietats per a la nova instància.

function Persona(){}
Persona.prototype.caminar = function(){return true;};
var pere = Persona();
assert(pere === undefined, "No s'ha creat cap instancia de Persona");

var jaume = new Persona();
assert(jaume && jaume.caminar && jaume.caminar(), "La instancia existeix i el mètode es pot cridar");

Podem veure en l'exemple anterior que pere te el valor undefined. Aixó és així per que la funció Persona, si no es crida amb el constructor new no retorna cap valor. Veiem que és veritat, ja que quan el cridem amb el constructor new Jaume existeix i a més a més té un mètode anomenat caminar.

Llavors, què és un prototip??

Un prototype és un objecte del que altres objectes hereten propietats.Aquest objecte pot ser qualsevol objecte. L'herència basada en classes no existeix en Javascript, sinó que és herència basada en prototips. Això significa que no hi ha una jerarquia de classes real (amb la seva extends, accés super, etc.), sinó que cada classe té un objecte de referència (com si fos la seva classe pare) on consultar atributs i mètodes en cas que la nostra classe no els trobi. Podem intentar simular una jerarquia (ull, simular) usant aquests objectes de referència, anomenats prototips, amb una propietat especial que tenen totes les “classes” anomenada prototype. Aquesta propietat és asignable i la seva labor consisteix a guardar un objecte. Vegem-ho amb un exemple:

var Saludator = function(nom) {
	this.nombre = nom
	this.saluda = function() {
		alert("hola "+this.nombre)
	}
}
// Añade un objeto al prototipo
Saludator.prototype = {
	apellido: "cruel",
	despide: function() {
		alert("adios "+this.nombre+" "+this.apellido)
	}
}
var obj1 = new Saludator("mundo")
obj1.despide() // "adios mundo cruel"


Quins objectes tenen prototip?

Tot objecte té un prototip per defecte. Com els prototips són objectes, tots ells tenen un prototip també. Solament hi ha una excepció: el prototip de l'objecte per defecte, al final de la cadena de prototips (Object).

Totes les classes tenen per defecte un objecte prototype buit, com si en crear-les es fes prototype = {}. Per aquesta raó, podem accedir a aquesta variable i assignar-li els atributs d'un en un. El següent exemple és completament equivalent a l'anterior:

var Saludator = function(nom) {
	this.nombre = nom
}
// Añade nuevas propiedades al prototipo
Saludator.prototype.apellido = "cruel"
Saludator.prototype.despide = function() {
	alert("adios "+this.nombre+" "+this.apellido)
}

var obj1 = new Saludator("mundo")
obj1.despide() // "adios mundo cruel"


Ok, recapitulem… què deies que era un objecte?

Un objecte en Javascript és una col·lecció qualsevol de parells clau-valor. Si no és un valor primitiu (undefined, null, boolean, number o string) és un objecte.

Utilitzant Prototips

Estudia aquest codi:

function Persona(){
	this.parat = false;
	this.caminar = function(){return !this.parat;};
}
Persona.prototype.caminar = function(){return this.parat;};

var joan = new Persona();

assert(joan.caminar(), "La crida a caminar és la crida definida dintre de Persona i no al mètode del prototip");

Creieu que és cert l'assert?? Doncs sí. Això demostra que el membres de la instància creats dintre del constructor bloquejaran les propietats i els mètodes definits amb el mateix nom en el prototip.

Com abordar les referències als mètodes i propietats dels prototips

Amb els exemples vistos anteriorment, pots arribar a pensar que quan es crea un nou objecte es copien els valors i els mètodes del seu prototip, i si hi ha algún mètode o propietat que s'anomena igual, es sobreescriu el seu valor amb el valor que hi ha en el constructor de l'objecte. Si fos així, en el següent codi, el mètode caminar no es podria utilitzar :

function Persona(){
	this.parat = true;
}
var joan = new Persona();
Persona.prototype.caminar = function(){return this.parat;};

assert(joan.caminar(), "El mètode existeix, fins i tot quan la persona s'ha creat abans.");

Llavors, aixó demostra que no hi ha una copia de propietats si no molt més. El que succeeix es que les funcions i mètodes del prototip s'adjunten a l'objecte construït i es consulta durant la conciliació de les referències de la propietat que es duen a terme en l'objecte. És a dir:

  • 1. Quan es fa una referència de propietat a un objecte, es comprova a veure si existeix en el propi objecte, si existeix s'agafa el valor, si no...
  • 2. Es localitza el prototip associat al objecte i es comprova si existeix la propietat, Si existeix es retorna el valor, si no...
  • 3. El valor es undefined