Objectes¶
Un objecte és una entitat que pot emmagatzemar diversos valors en propietats i mètodes.
- les propietats són valors identificats per un nom que representen característiques de l'objecte, i les podem llegir i escriure.
- els mètodes són definicions de funcions emmagatzemades com a valor d'una propietat, i representen accions específiques que pot realitzar un objecte.
Podem accedir a les propietats i mètodes d'un objecte amb l'operador punt .
darrera de la instància d'un objecte:
const objecte = new Object()
objecte.propietat = valor
let valor = objecte.propietat
objecte.mètode()
objecte.mètode( paràmetre )
JavaScript ens permet crear objectes amb diferents sintaxis:
Instància directa (sintaxi literal)¶
const cotxe = new Object() // Normalment NO s'utilitza aquesta sintaxi
const cotxe = {}
Les propietats poden ser de qualsevol tipus, inclosos altres objectes.
Podem assignar individualment valors a les propietats d'un objecte un cop creat:
const cotxe = {}
cotxe.marca = "Ford";
cotxe.model = "Fiesta";
cotxe.color = "vermell";
També podem utilitzar aquesta sintaxi a l'hora de referenciat les propietats d'un objecte:
const cotxe = {}
cotxe["marca"] = "Ford";
cotxe["model"] = "Fiesta";
cotxe["color"] = "vermell";
Això ens permet utilitzar variables com a nom de propietat, que pot ser convenient en alguns casos.
Finalment, podem assignar el valor de les propietat al moment de crear l'objecte:
const cotxe = { marca: "Ford", model: "Fiesta", color: "vermell" };
D'un tipus predefinit d'objecte en podem crear diverses instàncies utiltzant constructors.
Funció com a constructor¶
function cotxe( marcaCotxe, modelCotxe, colorCotxe )
{
this.marca = marcaCotxe;
this.model = modelCotxe;
this.color = colorCotxe;
}
Aquest constructor assigna 3 propietats (marca, model i color) a partir del valor dels paràmetres que rep la funció.
La paraula reservada this fa referència a la instància de l'objecte que crearem, i es posa davant de les propietats.
Per crear un nou objecte, utilitzem la funció com a constructor prefixant-la amb new
i passant els paràmetres de la funció en ordre:
var cotxe1 = new cotxe( "Ford", "Fiesta", "vermell" );
Mètodes¶
Per definir mètodes, creem funcions dins de la funció constructora posant davant seu la paraula reservada this:
function cotxe( marcaCotxe, modelCotxe, colorCotxe )
{
// Propietats
this.marca = marcaCotxe;
this.model = modelCotxe;
this.color = colorCotxe;
// Mètode
this.escriuCaracteristiques = function () {
return `${this.marca} ${this.model} de color ${this.color}`;
}
}
const cotxe1 = new cotxe( "Ford", "Fiesta", "vermell" );
let a = cotxe1.escriuCaracteristiques(); // 'Ford Fiesta de color vermell'
Prototipus¶
Tots els objectes de JavaScript hereten les seves propietats i mètodes d'un prototipus.
Per exemple, els objectes de la classe Date
hereten de Date.prototype
.
A través de la propietat prototype
podem afegir noves propietats i mètodes al constructor de qualsevol objecte sense reescriure'l.
Date.prototype.formatHorari = function( sep = ":" )
{
function posaZero( n ) { return String(n).padStart( 2,"0" ) };
return posaZero(this.getHours()) + sep +
posaZero(this.getMinutes()) + sep +
posaZero(this.getSeconds())
}
let ara = new Date()
ara.formatHorari() // Utilitza el mètode definit a la classe
No és recomanable modificar els prototipus dels objectes predefinits
Tot i que és possible fer-ho, es recomana NO modificar els prototipus dels objectes predefinits (Date, Array, etc.) ja que pot portar problemes de colisió de l'espai de noms com va passar amb el mètode flatten dels arrays, que va procat l'incident que es va conèixer com a SmooshGate.
Si ens cal fer-ho, és més recomanable extendre la classe amb un nom nou i afegir les noves propietats i mètodes allà.
Classes¶
Sintaxi introduïda a EcmaScript2015, és equivalent a utilitzar una funció com a constructor però amb una notació més ordenada i clara que s'acosta a com es realitza aquesta funció en altres llenguatges de programació.
Per crear una classe crearem un bloc amb la paraula reservada class
seguit del nom de la classe, i dins seu hi afegirem el mètode constructor()
amb els paràmetres necessaris, seguit de la resta de mètodes de la classe.
class nomClasse
{
constructor () { ... }
mètode1() { ... }
mètode2() { ... }
mètode3() { ... }
}
Només hi pot haver un sol constructor per cada classe.
El constructor s'executa automàticament quan instanciem un objecte de la classe amb new
, i el podem fer servir per inicialitzar propietats del nou objecte.
No cal declarar els mètodes com a funcions, però les propietats s'han de prefixar amb this.
Exemple:
class cotxe
{
constructor ( marcaCotxe, modelCotxe, colorCotxe )
{
// Propietats
this.marca = marcaCotxe;
this.model = modelCotxe;
this.color = colorCotxe;
}
// Mètode
escriuCaracteristiques() {
return `${this.marca} ${this.model} de color ${this.color}`;
}
}
const cotxe1 = new cotxe( "Ford", "Fiesta", "vermell" );
let a = cotxe1.escriuCaracteristiques(); // 'Ford Fiesta de color vermell'
Mode estricte activat
Si fem servir la notació de declaració de classes, tot el contingut de la declaració s'executarà automàticament en mode estricte.
Cal declarar les classes abans d'instanciar-les
Les declaracions de classe NO s'eleven automàticament (hoisting) com passa amb les funcions, per tant intentar instanciar un objecte de la classe abans de fer-ne la declaració provocarà un error.
Herència de classes¶
Treballant amb classes és molt fàcil crear classes filles d'una altra amb la paraula reservada extends.
Una classe creada amb herència hereta tots els mètodes de la seva classe pare i els pot sobrescriure, així com crear-ne de nous.
class cotxeElectric extends cotxe {
constructor ( marcaCotxe, modelCotxe, colorCotxe ) {
super( marcaCotxe, modelCotxe, colorCotxe );
this.electric = true;
}
escriuCaracteristiques() {
return super.escriuCaracteristiques() + " (elèctric)";
}
}
Amb la paraula reservada super
podem accedir a elements de l'element prototipus (aquell del qual estem heretant).
El mètode super()
invova al constructor de la classe pare, i només es pot utilizar dins del constructor.
En els punts del codi on invoquem super.mètode()
s'executarà el codi del mètode de la classe pare.
Per defecte totes les propietats i mètodes d'una classe són públics.
Propietats i mètodes privats
Des de la versió ES2020 de JavaScript es poden declarar propietats i mètodes privats.
Per fer-ho cal prefixar el seu nom amb #
.
Podem fer servir com a base d'herència objectes predefinits de JavaScript i així evitar modificar els seus prototipus:
class DataMillorada extends Date
{
#posaZero( n ) { return String(n).padStart( 2,"0" ) };
formatHorari( sep = ":" )
{
return this.#posaZero(this.getHours()) + sep +
this.#posaZero(this.getMinutes()) + sep +
this.#posaZero(this.getSeconds());
}
}
let ara = new DataMillorada()
ara.getHours() // Utilitza el mètode de l'objecte pare (Date)
ara.formatHorari() // Utilitza el mètode definit a la classe
ara.posaZero(1) // ERROR, mètode no trobat (és privat de la classe)
Propietats protegides¶
Amb la notació de classes podem utilitzat getters i setters per accedir a les propietats de forma controlada, per exemple per validar un valor a l'hora d'assignar-lo o bé formatar una resposta abans de donar-la.
El nom dels getters i setters no pot ser el mateix que el de la propietat sobre la que actuen.
Existeix el conveni de prefixar el nom de les propietats amb _
per distingir-les dels seus getters i setters:
class cotxe {
constructor ( marcaCotxe, anyCotxe )
{
// Propietats
this.marca = marcaCotxe;
this._any = anyCotxe;
}
// Getter
get any() {
return this._any;
}
// Setter
set any(x) {
// El setter pot fer comprovacions addicionals
if (x > 1900) this._any = x;
}
}
Encara que es declarin com a funcions, els getters i setters s'utilitzen sense parèntesis, com si fossin directament una propietat.
let cotxe1 = new cotxe( "Ford", 2020 );
cotxe1.any = 1880; // El codi del setter impedirà canviar l'any
cotxe1.any = 2018; // Es modificarà l'any
Podem crear arrays d'objectes:
var cotxes = new Array();
cotxes[0] = new cotxe("Ford", "Fiesta", "vermell");
cotxes[1] = new cotxe("Seat", "Ibiza", "blanc");
cotxes[2] = new cotxe("Toyota", "Prius", "negre");
cotxes[3] = new cotxe("Nissan", "Micra", "verd");
I el podem llegir i accedir a cada propietat:
for ( let cotxe of cotxes )
{
console.log( `<li>${cotxe.marca} ${cotxe.model}` );
}
Alternativament podem accedir a les propietats d'un objecte utilitzant el nom de propietat com a índex.
Les 3 instruccions següents són per tant equivalents:
var color = cotxe.color;
var color = cotxe[ "color" ];
let propietat = "color";
var color = cotxe[ propietat ];
Iteració d'objectes¶
Podem llegir seqüencialment totes les propietats d'un objecte utilitzant una iteració for..in
for ( let i in cotxe1 )
{
console.log( cotxe1[ i ] );
}
Tingueu en compte que...
Si hem fet servir una funció com a constructor, els mètodes se'ns retornaran també com a propietats que contenen el text de la funció.
Això no passarà si hem declarat l'objecte utilitzant class
.
Afegir mètodes i propietats¶
Podem afegir directament a un objecte propietats i mètodes que no formin part del constructor.
En aquest cas seran només d'aquella instància de l'objecte:
cotxes[0].anyFabricacio = 2008;
El primer cotxe de l'array tindrà la propietat anyFabricacio, però la resta d'instàncies de la classe "cotxe" no la tindran.