Come utilizzare argomenti e parametri ES6

Pubblicato: 2022-03-10
Riepilogo rapido ↬ Gli sviluppatori utilizzano sempre di più le funzionalità di ECMAScript 6 e presto queste funzionalità saranno inevitabili. In questo tutorial imparerai come ECMAScript 6 ha aggiornato la gestione dei parametri in JavaScript e altro ancora.

ECMAScript 6 (o ECMAScript 2015) è la versione più recente dello standard ECMAScript e ha notevolmente migliorato la gestione dei parametri in JavaScript. Ora possiamo utilizzare parametri di riposo, valori predefiniti e destrutturazione, tra le altre nuove funzionalità.

In questo tutorial, esploreremo argomenti e parametri in dettaglio e vedremo come ECMAScript 6 li ha aggiornati.

Argomenti contro parametri

Argomenti e parametri sono spesso indicati in modo intercambiabile. Tuttavia, ai fini di questo tutorial, faremo una distinzione. Nella maggior parte degli standard, i parametri (o parametri formali) sono ciò che viene fornito nella dichiarazione della funzione e gli argomenti (o parametri effettivi) sono ciò che viene passato alla funzione. Considera questa funzione:

 function foo(param1, param2) { // do something } foo(10, 20);

In questa funzione, param1 e param2 sono parametri di funzione e i valori passati alla funzione ( 10 e 20 ) sono argomenti.

Operatore di diffusione (...)

In ECMAScript 5, il metodo apply() è uno strumento utile per passare un array come argomenti a una funzione. Ad esempio, è comunemente usato con il metodo Math.max() per trovare il valore più alto in un array. Considera questo frammento di codice:

 var myArray = [5, 10, 50]; Math.max(myArray); // Error: NaN Math.max.apply(Math, myArray); // 50

Il metodo Math.max() non supporta gli array; accetta solo numeri. Quando un array viene passato alla funzione Math.max() , genera un errore. Ma quando viene utilizzato il metodo apply() , l'array viene inviato come numeri individuali, quindi il metodo Math.max() può gestirlo.

Altro dopo il salto! Continua a leggere sotto ↓

Fortunatamente, con l'introduzione dell'operatore spread in ECMAScript 6, non è più necessario utilizzare il metodo apply() . Con l'operatore spread, possiamo facilmente espandere un'espressione in più argomenti:

 var myArray = [5, 10, 50]; Math.max(...myArray); // 50

Qui, l'operatore spread espande myArray per creare valori individuali per la funzione. Sebbene sia possibile simulare l'operatore di diffusione utilizzando apply() in ECMAScript 5, la sintassi è confusa e manca della flessibilità dell'operatore di diffusione. L'operatore di diffusione non solo è più facile da usare, ma offre più funzioni. Ad esempio, può essere utilizzato più volte e può essere combinato con altri argomenti in una chiamata di function :

 function myFunction() { for(var i in arguments){ console.log(arguments[i]); } } var params = [10, 15]; myFunction(5, ...params, 20, ...[25]); // 5 10 15 20 25

Un altro vantaggio dell'operatore di diffusione è che può essere facilmente utilizzato con i costruttori:

 new Date(...[2016, 5, 6]); // Mon Jun 06 2016 00:00:00 GMT-0700 (Pacific Daylight Time)

Naturalmente, potremmo riscrivere il codice precedente in ECMAScript 5, ma avremmo bisogno di utilizzare un modello complicato per evitare di ottenere un errore di tipo:

 new Date.apply(null, [2016, 4, 24]); // TypeError: Date.apply is not a constructor new (Function.prototype.bind.apply(Date, [null].concat([2016, 5, 6]))); // Mon Jun 06 2016 00:00:00 GMT-0700 (Pacific Daylight Time)

Diffondere il supporto del browser dell'operatore nelle chiamate di funzione

Browser desktop:

Cromo Firefox Internet Explorer Microsoft Edge musica lirica Safari
46 27 Supportato 7.1

Browser mobili:

Chrome per Android Firefox Mobile Safari Mobile Opera Mobile IE Mobile
46 27 8

Parametri di riposo

Il parametro rest ha la stessa sintassi dell'operatore spread, ma invece di espandere un array in parametri, raccoglie i parametri e li trasforma in un array.

 function myFunction(...options) { return options; } myFunction('a', 'b', 'c'); // ["a", "b", "c"]

Se non ci sono argomenti, il parametro rest verrà impostato su un array vuoto:

 function myFunction(...options) { return options; } myFunction(); // []

Un parametro rest è particolarmente utile quando si crea una funzione variadica (una funzione che accetta un numero variabile di argomenti). Avendo il vantaggio di essere array, i parametri rest possono sostituire facilmente l'oggetto arguments (che spiegheremo più avanti in questo tutorial). Considera questa funzione, scritta in ECMAScript 5:

 function checkSubstrings(string) { for (var i = 1; i < arguments.length; i++) { if (string.indexOf(arguments[i]) === -1) { return false; } } return true; } checkSubstrings('this is a string', 'is', 'this'); // true

Questa funzione controlla se una stringa contiene un numero di sottostringhe. Il primo problema con questa funzione è che dobbiamo guardare all'interno del corpo della function per vedere che richiede più argomenti. Il secondo problema è che l'iterazione deve iniziare da 1 invece di 0 , perché arguments[0] punta al primo argomento. Se in seguito decidiamo di aggiungere un altro parametro prima o dopo la stringa, potremmo dimenticarci di aggiornare il ciclo. Con i parametri di riposo, evitiamo facilmente questi problemi:

 function checkSubstrings(string, ...keys) { for (var key of keys) { if (string.indexOf(key) === -1) { return false; } } return true; } checkSubstrings('this is a string', 'is', 'this'); // true

L'output di questa funzione è lo stesso della precedente. Anche in questo caso, la string del parametro viene riempita con l'argomento passato per primo, ma il resto degli argomenti viene inserito in un array e assegnato alla variabile keys .

L'uso del parametro rest invece dell'oggetto arguments migliora la leggibilità del codice ed evita problemi di ottimizzazione in JavaScript. Tuttavia, il parametro resto non è privo di limitazioni. Ad esempio, deve essere l'ultimo argomento; in caso contrario, si verificherà un errore di sintassi:

 function logArguments(a, ...params, b) { console.log(a, params, b); } logArguments(5, 10, 15); // SyntaxError: parameter after rest parameter

Un'altra limitazione è che nella dichiarazione della function è consentito un solo parametro rest:

 function logArguments(...param1, ...param2) { } logArguments(5, 10, 15); // SyntaxError: parameter after rest parameter

Supporto del browser per i parametri di riposo

Browser desktop:

Cromo Firefox Internet Explorer Microsoft Edge musica lirica Safari
47 15 Supportato 34

Browser mobili:

Chrome per Android Firefox Mobile Safari Mobile Opera Mobile IE Mobile
47 15

Parametri predefiniti

Parametri predefiniti in ECMAScript 5

JavaScript non supporta i parametri predefiniti in ECMAScript 5, ma esiste una soluzione semplice. Utilizzando un operatore OR logico ( || ) all'interno della funzione, possiamo simulare facilmente i parametri predefiniti in ECMAScript 5. Considera questa funzione:

 function foo(param1, param2) { param1 = param1 || 10; param2 = param2 || 10; console.log(param1, param2); } foo(5, 5); // 5 5 foo(5); // 5 10 foo(); // 10 10

Questa funzione prevede due argomenti, ma quando viene chiamata senza argomenti, utilizzerà i valori predefiniti. All'interno della funzione, gli argomenti mancanti vengono automaticamente impostati su undefined; quindi, possiamo rilevare questi argomenti e dichiarare valori predefiniti per loro. Per rilevare argomenti mancanti e impostare valori predefiniti, utilizziamo l'operatore OR logico ( || ). Questo operatore esamina il suo primo argomento: se è veritiero, l'operatore lo restituisce; in caso contrario, l'operatore restituisce il suo secondo argomento.

Questo approccio è comunemente usato nelle funzioni, ma ha un difetto. Il passaggio di 0 o null attiverà anche un valore predefinito, poiché questi sono considerati valori falsi. Quindi, se abbiamo effettivamente bisogno di passare 0 o null a questa funzione, avremmo bisogno di un modo alternativo per verificare se manca un argomento:

 function foo(param1, param2) { if(param1 === undefined){ param1 = 10; } if(param2 === undefined){ param2 = 10; } console.log(param1, param2); } foo(0, null); // 0, null foo(); // 10, 10

All'interno di questa funzione, i tipi di argomenti passati vengono controllati per assicurarsi che non siano definiti prima che vengano assegnati i valori predefiniti. Questo approccio richiede solo un po' più di codice, ma è un'alternativa più sicura e ci consente di passare 0 e null alla funzione.

Parametri predefiniti in ECMAScript 6

Con ECMAScript 6, non è più necessario verificare la presenza di valori non definiti per simulare i parametri predefiniti. Ora possiamo inserire i valori predefiniti direttamente nella dichiarazione della function :

 function foo(a = 10, b = 10) { console.log(a, b); } foo(5); // 5 10 foo(0, null); // 0 null

Come puoi vedere, l'omissione di un argomento attiva il valore predefinito, ma il passaggio di 0 o null non lo farà. Possiamo anche usare le funzioni per recuperare i valori per i parametri predefiniti:

 function getParam() { alert("getParam was called"); return 3; } function multiply(param1, param2 = getParam()) { return param1 * param2; } multiply(2, 5); // 10 multiply(2); // 6 (also displays an alert dialog)

Si noti che la funzione getParam viene chiamata solo se il secondo argomento viene omesso. Quindi, quando chiamiamo la funzione multiply() con due parametri, l'avviso non verrà visualizzato.

Un'altra caratteristica interessante dei parametri di default è che possiamo fare riferimento ad altri parametri e variabili nella dichiarazione della function :

 function myFunction(a=10, b=a) { console.log('a = ' + a + '; b = ' + b); } myFunction(); // a=10; b=10 myFunction(22); // a=22; b=22 myFunction(2, 4); // a=2; b=4

Puoi anche eseguire operazioni nella dichiarazione di function :

 function myFunction(a, b = ++a, c = a*b) { console.log(c); } myFunction(5); // 36

Nota che, a differenza di altri linguaggi, JavaScript valuta i parametri predefiniti al momento della chiamata:

 function add(value, array = []) { array.push(value); return array; } add(5); // [5] add(6); // [6], not [5, 6]

Supporto predefinito del browser dei parametri

Browser desktop:

Caratteristica Cromo Firefox Internet Explorer Microsoft Edge musica lirica Safari
Supporto di base 49 15 14
Parametri senza default dopo parametro default 49 26 14

Browser mobili:

Caratteristica Chrome per Android Firefox Mobile Safari Mobile Opera Mobile IE Mobile
Supporto di base 49 15
Parametri senza default dopo parametro default 46 26

Destrutturazione

La destrutturazione è una nuova funzionalità di ECMAScript 6 che ci consente di estrarre valori da array e oggetti e di assegnarli a variabili utilizzando una sintassi simile agli oggetti e ai valori letterali di array. La sintassi è chiara e di facile comprensione ed è particolarmente utile quando si passano argomenti a una funzione.

In ECMAScript 5, un oggetto di configurazione viene spesso utilizzato per gestire un numero elevato di parametri facoltativi, soprattutto quando l'ordine delle proprietà non ha importanza. Considera questa funzione:

 function initiateTransfer(options) { var protocol = options.protocol, port = options.port, delay = options.delay, retries = options.retries, timeout = options.timeout, log = options.log; // code to initiate transfer } options = { protocol: 'http', port: 800, delay: 150, retries: 10, timeout: 500, log: true }; initiateTransfer(options);

Questo modello è comunemente usato dagli sviluppatori JavaScript e funziona bene, ma dobbiamo guardare all'interno del corpo della function per vedere quali parametri si aspetta. Con i parametri destrutturati, possiamo indicare chiaramente i parametri nella dichiarazione di function :

 function initiateTransfer({protocol, port, delay, retries, timeout, log}) { // code to initiate transfer }; var options = { protocol: 'http', port: 800, delay: 150, retries: 10, timeout: 500, log: true } initiateTransfer(options);

In questa funzione, abbiamo utilizzato un modello di destrutturazione degli oggetti, invece di un oggetto di configurazione. Questo rende la nostra funzione non solo più concisa, ma anche più facile da leggere.

Possiamo anche combinare parametri destrutturati con parametri regolari:

 function initiateTransfer(param1, {protocol, port, delay, retries, timeout, log}) { // code to initiate transfer } initiateTransfer('some value', options);

Si noti che verrà generato un errore di tipo se i parametri vengono omessi nella chiamata di function :

 function initiateTransfer({protocol, port, delay, retries, timeout, log}) { // code to initiate transfer } initiateTransfer(); // TypeError: Cannot match against 'undefined' or 'null'

Questo è il comportamento desiderato quando è necessario che i parametri siano obbligatori, ma cosa succede se vogliamo che siano facoltativi? Per evitare questo errore quando mancano parametri, dobbiamo assegnare un valore predefinito ai parametri destrutturati:

 function initiateTransfer({protocol, port, delay, retries, timeout, log} = {}) { // code to initiate transfer } initiateTransfer(); // no error

In questa funzione viene fornito un oggetto vuoto come valore predefinito per i parametri destrutturati. Ora, se questa funzione viene chiamata senza alcun parametro, non si verificherà alcun errore.

Possiamo anche assegnare un valore di default ad ogni parametro destrutturato:

 function initiateTransfer({ protocol = 'http', port = 800, delay = 150, retries = 10, timeout = 500, log = true }) { // code to initiate transfer }

In questo esempio, ogni proprietà ha un parametro predefinito, eliminando la necessità di controllare manualmente parametri non definiti e assegnare valori predefiniti all'interno del corpo della function .

Destrutturazione del supporto del browser

Browser desktop:

Caratteristica Cromo Firefox Internet Explorer Microsoft Edge musica lirica Safari
Supporto di base 49 2.0 14 7.1
Parametro destrutturato con assegnazione del valore di default 49 47 14

Browser mobili:

Caratteristica Chrome per Android Firefox Mobile Safari Mobile Opera Mobile IE Mobile
Supporto di base 49 1 8
Parametri senza default dopo parametro default 49 47

Argomenti di passaggio

Esistono due modi per passare argomenti a una funzione: per riferimento o per valore. La modifica di un argomento passato per riferimento si riflette a livello globale, ma la modifica di un argomento passato per valore si riflette solo all'interno della funzione.

In alcuni linguaggi, come Visual Basic e PowerShell, abbiamo la possibilità di specificare se passare un argomento per riferimento o per valore, ma non è il caso di JavaScript.

Passare argomenti per valore

Tecnicamente, JavaScript può passare solo per valore. Quando si passa un argomento a una funzione in base al valore, viene creata una copia di quel valore all'interno dell'ambito della function . Pertanto, qualsiasi modifica al valore si riflette solo all'interno della function . Considera questo esempio:

 var a = 5; function increment(a) { a = ++a; console.log(a); } increment(a); // 6 console.log(a); // 5

Qui, la modifica dell'argomento all'interno della funzione non ha alcun effetto sul valore originale. Quindi, quando la variabile viene registrata dall'esterno della funzione, il valore stampato è ancora 5 .

Passare argomenti per riferimento

In JavaScript, tutto viene passato per valore, ma quando passiamo una variabile che fa riferimento a un oggetto (inclusi gli array), il "valore" è un riferimento all'oggetto e la modifica di una proprietà di un oggetto a cui fa riferimento una variabile cambia il oggetto sottostante.

Considera questa funzione:

 function foo(param){ param.bar = 'new value'; } obj = { bar : 'value' } console.log(obj.bar); // value foo(obj); console.log(obj.bar); // new value

Come puoi vedere, la proprietà dell'oggetto viene modificata all'interno della funzione, ma il valore modificato è visibile all'esterno della funzione.

Quando si passa un valore non primitivo come un array o un oggetto, dietro la scena viene creata una variabile che punta alla posizione dell'oggetto originale in memoria. Questa variabile viene quindi passata alla funzione e la modifica influirà sull'oggetto originale.

Digitare Verifica e parametri mancanti o extra

In un linguaggio fortemente tipizzato, dobbiamo specificare il tipo di parametri nella dichiarazione della function , ma JavaScript non ha questa caratteristica. In JavaScript, non importa quale tipo di dati o quanti argomenti passiamo a una funzione.

Supponiamo di avere una funzione che accetta un solo argomento. Quando chiamiamo quella funzione, non siamo limitati a passare un solo argomento alla funzione; siamo liberi di passare uno, due o più argomenti! Potremmo anche scegliere di non trasmettere nulla e non si verificheranno errori.

Il numero di argomenti e parametri può differire in due modi:

  • Meno argomenti che parametri .
    I parametri mancanti saranno uguali a undefined .
  • Più argomenti che parametri .
    I parametri extra verranno ignorati ma possono essere recuperati tramite gli speciali argomenti variabili simili a array (discussi in seguito).

Argomenti obbligatori

Se un argomento manca in una chiamata di function , verrà impostato su undefined . Possiamo sfruttare questo comportamento e generare un errore se viene omesso un argomento:

 function foo(mandatory, optional) { if (mandatory === undefined) { throw new Error('Missing parameter: mandatory'); } }

In ECMAScript 6, possiamo andare oltre e utilizzare i parametri predefiniti per impostare argomenti obbligatori:

 function throwError() { throw new Error('Missing parameter'); } function foo(param1 = throwError(), param2 = throwError()) { // do something } foo(10, 20); // ok foo(10); // Error: missing parameter

Argomenti Oggetto

Il supporto per i parametri rest è stato aggiunto a ECMAScript 4 con l'intenzione di sostituire l'oggetto arguments , ma ECMAScript 4 non è mai stato realizzato. Con il rilascio di ECMAScript 6, JavaScript ora supporta ufficialmente i parametri resto. Ha anche annullato il piano per eliminare il supporto per l'oggetto arguments .

L'oggetto arguments è un oggetto simile a un array disponibile all'interno di tutte le funzioni. Consente di recuperare i valori argument passati alla funzione per numero, anziché per nome. L'oggetto ci consente di passare un numero qualsiasi di argomenti a una funzione. Considera il seguente frammento di codice:

 function checkParams(param1) { console.log(param1); // 2 console.log(arguments[0], arguments[1]); // 2 3 console.log(param1 + arguments[0]); // 2 + 2 } checkParams(2, 3);

Questa funzione prevede di ricevere un solo argomento. Quando lo chiamiamo con due argomenti, il primo argomento è accessibile nella funzione tramite il nome del parametro param1 o l'oggetto arguments[0] , ma il secondo argomento è accessibile solo come arguments[1] . Si noti inoltre che l'oggetto arguments può essere utilizzato insieme ad argomenti denominati.

L'oggetto arguments contiene una voce per ogni argomento passato alla funzione e l'indice della prima voce inizia da 0 . Se volessimo accedere a più argomenti nell'esempio sopra, scriveremmo arguments[2] , arguments[3] e così via.

Potremmo anche saltare del tutto l'impostazione dei parametri denominati e utilizzare semplicemente l'oggetto arguments :

 function checkParams() { console.log(arguments[1], arguments[0], arguments[2]); } checkParams(2, 4, 6); // 4 2 6

In effetti, i parametri denominati sono una comodità, non una necessità. Allo stesso modo, i parametri rest possono essere utilizzati per riflettere gli argomenti passati:

 function checkParams(...params) { console.log(params[1], params[0], params[2]); // 4 2 6 console.log(arguments[1], arguments[0], arguments[2]); // 4 2 6 } checkParams(2, 4, 6);

L'oggetto arguments è un oggetto simile a un array, ma manca di metodi di array come slice() e foreach() . Per utilizzare i metodi array sull'oggetto arguments , l'oggetto deve prima essere convertito in un array reale:

 function sort() { var a = Array.prototype.slice.call(arguments); return a.sort(); } sort(40, 20, 50, 30); // [20, 30, 40, 50]

In questa funzione, Array.prototype.slice.call() viene utilizzato come metodo rapido per convertire l'oggetto arguments in un array. Successivamente, il metodo sort() ordina gli elementi dell'array e lo restituisce.

ECMAScript 6 ha un modo ancora più semplice. Array.from() , una nuova aggiunta in ECMAScript 6, crea un nuovo array da qualsiasi oggetto simile a un array:

 function sort() { var a = Array.from(arguments); return a.sort(); } sort(40, 20, 50, 30); // [20, 30, 40, 50]

La proprietà della lunghezza

Sebbene l'oggetto arguments non sia tecnicamente un array, ha una proprietà length che può essere utilizzata per controllare il numero di argomenti passati a una funzione:

 function countArguments() { console.log(arguments.length); } countArguments(); // 0 countArguments(10, null, "string"); // 3

Utilizzando la proprietà length , abbiamo un migliore controllo sul numero di argomenti passati a una funzione. Ad esempio, se una funzione richiede due argomenti per funzionare, è possibile utilizzare la proprietà length per verificare il numero di argomenti passati e generare un errore se sono inferiori al previsto:

 function foo(param1, param2) { if (arguments.length < 2) { throw new Error("This function expects at least two arguments"); } else if (arguments.length === 2) { // do something } }

I parametri Rest sono matrici, quindi hanno una proprietà di length . In ECMAScript 6 il codice precedente può essere riscritto con parametri rest:

 function foo(...params) { if (params.length < 2) { throw new Error("This function expects at least two arguments"); } else if (params.length === 2) { // do something } }

Le proprietà del chiamato e del chiamante

La proprietà callee fa riferimento alla funzione attualmente in esecuzione e il caller fa riferimento alla funzione che ha chiamato la funzione attualmente in esecuzione. Nella modalità rigorosa di ECMAScript 5, queste proprietà sono deprecate e il tentativo di accedervi provoca un TypeError.

La proprietà arguments.callee è utile nelle funzioni ricorsive (una funzione ricorsiva è una funzione regolare che si riferisce a se stessa con il suo nome), specialmente quando il nome della funzione non è disponibile (una funzione anonima). Poiché una funzione anonima non ha un nome, l'unico modo per farvi riferimento è tramite arguments.callee .

 var result = (function(n) { if (n <= 1) { return 1; } else { return n * arguments.callee(n - 1); } })(4); // 24

Argomenti oggetto in modalità rigorose e non rigorose

Nella modalità non rigorosa di ECMAScript 5, l'oggetto arguments ha una caratteristica insolita: mantiene i suoi valori sincronizzati con i valori dei parametri denominati corrispondenti.

Considera il seguente frammento di codice:

 function foo(param) { console.log(param === arguments[0]); // true arguments[0] = 500; console.log(param === arguments[0]); // true return param } foo(200); // 500

All'interno di questa funzione, viene assegnato un nuovo valore agli arguments[0] . Poiché i valori degli arguments rimangono sempre sincronizzati con i valori dei parametri denominati, la modifica agli arguments[0] cambierà anche il valore di param . In effetti, sono come due nomi diversi per la stessa variabile. Nella modalità rigorosa di ECMAScript 5, questo comportamento confuso dell'oggetto arguments è stato rimosso:

 "use strict"; function foo(param) { console.log(param === arguments[0]); // true arguments[0] = 500; console.log(param === arguments[0]); // false return param } foo(200); // 200

Questa volta, la modifica degli arguments[0] non influisce su param e l'output è come previsto. L'output di questa funzione in ECMAScript 6 è lo stesso della modalità rigorosa di ECMAScript 5, ma tieni presente che quando nella dichiarazione della function vengono utilizzati valori predefiniti, l'oggetto arguments non è interessato:

 function foo(param1, param2 = 10, param3 = 20) { console.log(param1 === arguments[0]); // true console.log(param2 === arguments[1]); // true console.log(param3 === arguments[2]); // false console.log(arguments[2]); // undefined console.log(param3); // 20 } foo('string1', 'string2');

In questa funzione, anche se param3 ha un valore predefinito, non è uguale ad arguments[2] perché alla funzione vengono passati solo due argomenti. In altre parole, l'impostazione dei valori predefiniti non ha alcun effetto sull'oggetto arguments .

Conclusione

ECMAScript 6 ha apportato centinaia di piccoli e grandi miglioramenti a JavaScript. Sempre più sviluppatori utilizzano le funzionalità di ECMAScript 6 e presto queste funzionalità saranno inevitabili. In questo tutorial, abbiamo appreso come ECMAScript 6 ha aggiornato la gestione dei parametri in JavaScript, ma abbiamo appena scalfito la superficie di ECMAScript 6. Vale la pena dare un'occhiata a molte altre nuove e interessanti funzionalità del linguaggio.

Collegamenti

  • Tabella di compatibilità ECMAScript 6, Juriy Zaytsev
  • "Specifica del linguaggio ECMAScript 2015", ECMA International