JavaScript: le nuove caratteristiche degli oggetti introdotte in ECMAScript 5.1

JavaScript: le nuove caratteristiche degli oggetti introdotte in ECMAScript 5.1

In questo articolo parleremo delle nozioni fondamentali degli oggetti così come sono state definite in ECMAScript 5.1.

Un nuovo modo di concepire gli oggetti

In JavaScript gli oggetti sono coppie formate da una chiave e da un valore. Per esempio se volessi descrivere il mio nome completo avrei un oggetto con due chiavi: firstName punterebbe a Gabriele e lastName a Romanato. Le chiavi in questo caso sono stringhe.

Per creare un oggetto vuoto useremo il seguente codice:

var Person = Object.create(null);

Ora abbiamo un oggetto vuoto. Prima di aggiungervi delle proprietà è necessario capire come viene considerata una proprietà in JavaScript.

Una proprietà ha un nome ed un valore. Inoltre una proprietà può essere enumerable, configurable e writable.

Se è enumerable, ciò significa che verrà mostrata in un loop for..in. Se è writable, può essere sovrascritta. Se è configurable, possiamo eliminarla o modificare i suoi attributi.

Aggiungere proprietà

In genere quando creiamo una nuova proprietà noi desideriamo che abbia tutti questi attributi. Infatti prima di ECMAScript 5, questo era l'unico modo di creare delle proprietà.

Possiamo aggiungere delle proprietà ad un oggetto utilizzando il metodo Object.defineProperty:

var Person = Object.create(null);
Object.defineProperty(Person, 'firstName', {
    value: 'Gabriele',
    writable: true,
    enumerable: true,
    configurable: true
});

Object.defineProperty(Person, 'lastName', {
    value: 'Romanato',
    writable: true,
    enumerable: true,
    configurable: true
});

Possiamo rendere questa procedura meno prolissa definendo una sola volta i valori predefiniti:

var config = {
    writable: true,
    enumerable: true,
    configurable: true
};

var defineProperty = function(obj, name, value) {
    config.value = value;
    Object.defineProperty(obj, name, config);
};

var Person = Object.create(null);
defineProperty(Person, 'firstName', 'Gabriele');
defineProperty(Person, 'lastName', 'Romanato');

La proprietà prototype

In JavaScript gli oggetti hanno inoltre un attributo aggiuntivo: un puntatore ad un altro oggetto. Chiamiamo questo puntatore ´prototype`.

L'interprete JavaScript quando cerca una proprietà in un oggetto e non la trova, allora la cercherà nel suo prototype. Seguirà la catena del prototype fino a quando non troverà un valore null, nel qual caso restituirà undefined.

Avrete notato che abbiamo creato l'oggetto Personusando Object.create(null). Il parametro di questo metodo stabilisce cosa debba essere usato come prototype dell'oggetto creato.

Possiamo verificare quale sia l'effettivo prototype di un oggetto utilizzando il metodo Object.getPrototypeOf:

var Developer = Object.create(null);
defineProperty(Developer, 'job', 'developer');
var Gabriele = Object.create(Developer);
defineProperty(Gabriele, 'firstName', 'Gabriele');
defineProperty(Gabriele, 'lastName', 'Romanato');

Gabriele.job // 'developer'
Gabriele.firstName // 'Gabriele'
Gabriele.lastName  // 'Romanato'

Object.getPrototypeOf(Gabriele)
// restituisce l'oggetto Developer

Possiamo anche aggiungere metodi che verranno condivisi dai vari oggetti:

var Person = Object.create(null);
defineProperty(Person, 'getFullName', function() {
    return this.firstName + ' ' + this.lastName;
});

var Developer = Object.create(Person);
defineProperty(Developer, 'job', 'developer');

var Gabriele = Object.create(Developer);
defineProperty(Gabriele, 'firstName', 'Gabriele');
defineProperty(Gabriele, 'lastName', 'Romanato');

Gabriele.job  // 'developer'
Gabriele.getFullName()  // 'Gabriele Romanato'

Object.defineProperties

Questo metodo è un utile scorciatoia per impostare più di una proprietà di un oggetto.

Accetta due parametri:

  1. object L'oggetto su cui definire le proprietà.
  2. properties Un oggetto le cui proprietà specificano quali proprietà definire o modificare sull'oggetto.

Esempio:

var Test = Object.create(null);
Object.defineProperties(Test, {
    'property1': {
       value: 'Test',
       writable: true
     },
     'property2': {
        value: 'Test 2',
        writable: true
      }
});

Test.property1 // 'Test'
Test.property2 // 'Test 2'

Controllare l'ereditarietà

In JavaScript, come in altri linguaggi OO, l'ereditarietà è la caratteristica che permette di estendere gli oggetti facendo loro ereditare le proprietà di un altro oggetto.

ECMAScript 5 fornisce due metodi per controllare e verificare l'ereditarietà degli oggetti:

  1. `Object.preventExtensions(obj)
  2. `Object.isExtensible(obj)

Il primo metodo "congela" un oggetto ed impedisce che possa ricevere in futuro nuove proprietà, mentre il secondo verifica se un oggetto può essere esteso.

Un esempio:

var Person = {};
Person.name = 'Gabriele';
console.log(Person.name); // 'Gabriele'

console.log(Object.isExtensible(Person)); // true

Object.preventExtensions(Person);

Person.job = 'developer';
// Solleva un'eccezione nella modalità strict di ECMA5

console.log(Object.isExtensible(Person)); // false

Altri metodi che gestiscono la modifica degli oggetti da parte di altre parti del codice sono:

  • Object.seal(obj) - Impedisce di cancellare i descrittori delle proprietà di un oggetto e di aggiungere nuove proprietà.
  • Object.isSealed(obj)- Verifica che l'oggetto sia stato "bloccato" dal metodo precedente.
  • Object.freeze(obj) - Identico al primo metodo, con l'aggiunta di rendere le proprietà esistenti non modificabili.
  • Object.isFrozen(obj)- Verifica che l'oggetto sia stato "congelato" dal metodo precedente.

Elencare le proprietà di un oggetto

Se una proprietà di un oggetto è elencabile (enumerable), questa sarà visibile in un tradizionale loop for...in. ECMAScript 5 ci fornisce una comoda scorciatoia per ottenere i nomi delle proprietà di un oggetto:

Object.keys(obj)

Questo metodo restituisce un array di stringhe che rappresentano tutti i nomi delle proprietà elencabili di un oggetto. Esempio:

var Person = {
    name: 'Gabriele',
    job: 'developer'
};

console.log(Object.keys(Person).join(', '));
// 'name', 'job'

Analogo a questo metodo è il metodo Object.getOwnPropertyNames che a differenza del precedente restituisce un array di tutti i nomi delle proprietà di un oggetto, anche quelle che non sono elencabili.

Torna su