Javascript Coercion [2] Explicit Coercion

J
Questo articolo fa parte di una serie di articoli:

  1. Javascript Coercion [1] Abstract Value Operations
  2. Javascript Coercion [2] Explicit Coercion
  3. Javascript Coercion [3] Implicit Coercion
  4. Javascript Coercion [4] Loose Equality

 

EXPLICIT COERCION

Proseguiamo il nostro viaggio nel meraviglioso mondo della coercizione in Javascript considerando i casi principali dove essa può essere definita esplicita. Sebbene questo termine non ha e non avrà mai un confine ben preciso, possiamo definire espliciti tutti i casi di coercizione dove la conversione avviene in maniera chiara, diretta e ovvia sia per noi stessi che scriviamo il codice, sia per altre persone che lo potrebbero dover interpretare in futuro.

 

To string explicit coercion

La coercizione esplicita di un valore nel tipo stringa avviene tramite una chiamata alla built-in function String(), passandole in input il valore da convertire. Essa chiamerà in causa la ToString abstract operation che abbiamo discusso nel precedente articolo.

Qualche esempio:

var foo = 42;
var bar = {};
var baz = [0, 1, 2, 3];

String(foo); // "42"
String(bar); // "[object Object]"
String(baz); // "0,1,2,3"

Dato che la ToString abstract operation si basa principalmente sul metodo toString() possiamo scegliere di invocarlo direttamente anziché affidarci all’operazione astratta:

var foo = 42; 
var bar = {}; 
var baz = [0, 1, 2, 3]; 

foo.toString(); // "42" 
bar.toString(); // "[object Object]" 
baz.toString(); // "0,1,2,3"

Se il fatto che la chiamata sulla variabile foo vada a buon fine vi lascia spaesati, poiché sembra che anche i valori primitivi possiedano proprietà, dovete sapere che in tutti i casi in cui un valore primitivo viene utilizzato come un oggetto, il Javascript ne ingloba in automatico il valore primitivo in un oggetto wrapper adatto alle circostanze. Non è lo scopo di questo articolo approfondirne i dettagli, ma è questo meccanismo che permette in Javascript di eseguire correttamente la seguente istruzione:

(42).toString(); // "42"

 

To NUMBER explicit coercion

La coercizione esplicita di un valore nel tipo numerico avviene tramite una chiamata alla built-in function Number(), passandole in input il valore da convertire. Essa chiamerà in causa la ToNumber abstract operation che abbiamo discusso nel precedente articolo.

Qualche esempio:

var foo = "42";
var bar = {};
var baz = [10];

Number(foo); // 42
Number(bar); // NaN
Number(baz); // 10

Anche se la che la ToNumber abstract operation si basa prima di tutto sul metodo valueOf(), nel precedente articolo abbiamo visto perché spesso deve entrare in gioco il metodo toString(). Perciò, a meno di casi particolari dove siamo sicuri al 10

Una valida alternativa consiste nell’uso dell’operatore unario “+”. Esso invoca la ToNumber abstract operation esattamente come la la built-in function Number(). Si potrebbe discutere sulla validità del considerare l’uso dell’operatore sopracitato un’operazione esplicita, ma esso è entrato nell’uso comune della maggior parte degli sviluppatori Javascript proprio per eseguire questa operazione, perciò la comunità JS lo considera quasi all’unanimità una forma di coercizione esplicita.

var foo = "42"; 
var bar = {}; 
var baz = [10]; 

+foo; // 42
+bar; // NaN 
+baz; // 10

È possibile utilizzare l’operatore unario “-” per ottenere il medesimo risultato con il segno invertito:

var foo = "42";
var bar = {};
var baz = [10];

-foo; // -42
-bar; // NaN (-NaN non esiste!)
-baz; // -10

 

L’operatore ~

Un’altro operatore che coercizza il valore su cui è chiamato in un valore di tipo numerico è l’operatore tilde (bitwise NOT). Le operazioni bitwise non sono valide su tutti i valori numerici: essi devono essere valori interi e compresi nel range 2^31 – 1 ÷ 2^-31, estremi inclusi. L’operatore tilde si basa sulla ToInt32 abstract operation, la quale invoca immediatamente la la ToNumber abstract operation sul valore in questione, per poi apportare qualche altra modifica. Elenchiamo i principali risultati della ToInt32 abstract operation:

  • se la ToNumber abstract operation produce NaN, Infinity, -Infinity otteniamo 0
  • se la ToNumber abstract operation produce un valore intero che ricade nel range sopracitato, il valore restituito è pari a questo valore appena ottenuto
  • se la ToNumber abstract operation produce un valore intero che non ricade nel range sopracitato, il valore restituito non è facilmente predicibile dato che è presente una situazione di overflow
  • se la ToNumber abstract operation produce un valore non-intero otteniamo il medesimo valore senza la parte decimale, a patto che esso ricada nel range sopracitato per non incorrere nelle medesime problematiche del punto precedente

Perciò, prima di effettuare l’operazione di bitwise NOT, il Javascript esegue una coercizzazione del valore nel tipo numerico, per poi eventualmente modificare il valore stesso, non il tipo che da numerico rimane numerico, seguendo le poche regole appena citate.

L’operazione di bitwise NOT su un valore x numerico esegue il complemento a due, che corrisponde alla seguente operazione: -(x+1). Quando potrebbe esserci utile? Riflettiamo un momento. Qual’è l’unico valore numerico sul quale è possibile effettuare questa operazione per ottenere 0 come risultato? Esatto, è -1. Spesso questo valore è utilizzato come valore sentinella, venendo restituito come valore di ritorno da una moltitudine di funzioni in vari linguaggi per indicare un falimento.

Prendiamo come esempio il metodo indexOf() disponibile in JS per tutti gli oggetti array. Esso viene utilizzato per conoscere l’indice di un determinato valore cercato dentro l’array stesso. Dato che gli array usano solo indici >= 0, è stato scelto -1 come valore di ritorno di questa funzione per indicare che il valore ricercato non è stato trovato. Perciò un listato come il seguente che rende evidente un dettaglio implementativo:

var arr = [0, 1, 2];

if(arr.indexOf(1) >= 0) {
    // value found
}

if(arr.indexOf(1) == -1) {
    // value not found
}

può essere mascherato utilizzando l’operatore tilde:

var arr = [0, 1, 2];

if(~arr.indexOf(1)) {
    // value found
}

if(!~arr.indexOf(1)) {
    // value not found
}

 

L’operatore tilde può anche essere utilizzato due volte consecutivamente sul medesimo valore numerico per eliminare la parte decimale lasciando invariato il segno:

var foo = 42.7;
var bar = -42.3;

~~foo; // 42
~~bar; // -42

 

To BOOLEAN explicit coercion

La coercizione esplicita di un valore nel tipo booleano avviene tramite una chiamata alla built-in function Boolean(), passandole in input il valore da convertire. Essa chiamerà in causa la ToBoolean abstract operation che abbiamo discusso nel precedente articolo.

var foo = "42"; 
var bar = {}; 
var baz = 0; 

Boolean(foo); // true
Boolean(bar); // true 
Boolean(baz); // false

Una valida, e decisamente più comune, alternativa consiste nell’uso dell’operatore unario “!” (NOT). Esso invoca la ToBoolean abstract operation esattamente come la la built-in function Boolean(), invertendo però il risultato. Per questo non è difficile trovare del codice che utilizza l’operatore “!” due volte consecutivamente:

var foo = "42"; 
var bar = {}; 
var baz = 0; 

!foo; // false
!bar; // false
!baz; // true

!!foo; // true
!!bar; // true 
!!baz; // false

 

CONCLUSIONE

Possiamo chiudere qui la disamina dei più comuni casi di coercizione esplicita. Spero vivamente che, unendo le conoscenze di questo e del precedente articolo, la coercizione stia diventando mano mano meno oscura e misteriosa. Nel prossimo articolo affronteremo, per la gioia di tutti, la coercizione implicita. Riusciremo a sopravvivere?

A proposito di me

Andrea Simone Costa

Classe 1997, Toscano DOCP, Asimov oriented.
Si è diplomato come perito elettronico, ma ha ben presto tradito le origini per immergersi nell'universo JavaScript. Ama condividere ciò che ha imparato in modo semplice e pragmatico, senza mai ricadere nel banale, coltivando segretamente il sogno di insegnare.

Gli articoli più letti

Articoli recenti

Commenti recenti