Quali sono le semantiche precise delle funzioni a livello di blocco in ES6?

Sto cercando di comprendere le nuove funzioni a livello di blocco standardizzate in ES6 leggendo le specifiche raw. La mia comprensione superficiale era:

  • Le dichiarazioni delle funzioni a livello di blocco sono consentite in ES6.
  • Si issano in cima all’isolato.
  • In modalità rigorosa, non sono visibili al di fuori del blocco contenitore.

Tuttavia, ciò è ulteriormente complicato dal fatto che parte di queste semantiche è specificata come “facoltativa” e solo obbligatoria per i browser Web ( Allegato B ). Quindi vorrei avere la seguente tabella compilata:

                                              |  Visibile al di fuori del blocco?  |  Issato?  Fino a che punto?  |  "TDZ"?  |  -------------------------------------------------- -------------------------------------------------- -------------------- |  Modalità non rigida, nessuna "estensione web" |  |  |  |  |  Modalità rigorosa, senza "estensioni web" |  |  |  |  |  Modalità non rigida, con "estensioni web | | | | | Modalità rigorosa, con" estensioni web "| | | | 

Inoltre non è chiaro per me cosa significa “modalità rigorosa” in questo contesto. Questa distinzione sembra essere introdotta nell’allegato B3.3 , come parte di alcuni passaggi aggiuntivi per l’esecuzione runtime di una dichiarazione di funzione:

1. If strict is false, then ... 

Tuttavia, per quanto posso vedere, strict fa riferimento allo slot interno [[Strict]] dell’object funzione. Questo significa che:

 // Non-strict surrounding code { function foo() {"use strict";} } 

dovrebbe essere considerato “strict mode” nella tabella sopra? Tuttavia, questo è in contraddizione con la mia intuizione iniziale.

Tieni presente che sono principalmente interessato alle specifiche ES6, indipendentemente dalle reali incongruenze di implementazione.

Per quanto posso vedere, strict riferisce allo slot interno [[Strict]] dell’object funzione.

No. E si. Fa riferimento alla severità della funzione ( o dello script ) in cui si verifica il blocco che contiene la dichiarazione della funzione. Non alla severità della funzione che è (o non è) da dichiarare.

Le “estensioni web” si applicano solo al codice sciatto (non rigido) e solo se l’aspetto dell’istruzione della funzione è “sensato”, ovvero, ad esempio, se il suo nome non collide con un parametro formale o lessicalmente variabile dichiarata.

Si noti che non vi è alcuna differenza tra codice rigoroso e sciatto senza la semantica della compatibilità Web. In ES6 puro, esiste un solo comportamento per le dichiarazioni di funzione nei blocchi.

Quindi fondamentalmente lo abbiamo

  | web-compat pure -----------------+--------------------------------------------- strict mode ES6 | block hoisting block hoisting sloppy mode ES6 | it's complicated ¹ block hoisting strict mode ES5 | undefined behavior ² SyntaxError sloppy mode ES5 | undefined behavior ³ SyntaxError 

1: Vedi sotto. Gli avvisi sono richiesti.
2: in genere viene generato un SyntaxError
3: La nota di ES5.1 §12 parla di ” variazioni significative e inconciliabili tra le implementazioni ” (come queste ). Si raccomandano avvertimenti.

Quindi, ora come si comporta un’attuazione ES6 con la compatibilità Web per una dichiarazione di funzione in un blocco in una funzione in modalità trascurata con semantica legacy?
Prima di tutto, si applica ancora la semantica pura . Cioè, la dichiarazione della funzione viene issata all’inizio del blocco lessicale.
Tuttavia, esiste anche una dichiarazione var che viene issata nella parte superiore della funzione di chiusura.
E quando viene valutata la dichiarazione della funzione (nel blocco, come se fosse stata soddisfatta come un’istruzione), l’object funzione viene assegnato a quella variabile dell’ambito della funzione.

Questo è meglio spiegato dal codice:

 function enclosing(…) { … { … function compat(…) { … } … } … } 

funziona allo stesso modo di

 function enclosing(…) { var compat₀ = undefined; // function-scoped … { let compat₁ = function compat(…) { … }; // block-scoped … compat₀ = compat₁; … } … } 

Sì, questo è un po ‘confuso, con due collegamenti diversi (indicati con gli indici 0 e 1) con lo stesso nome. Quindi ora posso rispondere brevemente alle tue domande:

Visibile al di fuori del blocco?

Sì, come una var . Tuttavia, c’è un secondo legame visibile solo all’interno del blocco.

Issato?

Sì, due volte.

Fino a che punto?

Sia alla funzione (comunque inizializzata con undefined ) che al blocco (inizializzato con l’object funzione).

“TDZ”?

Non nel senso della zona morta temporale di una variabile dichiarata lessicalmente ( let / const / class ) che si basa sul riferimento, no. Ma prima che si verifichi la dichiarazione della funzione nell’esecuzione del corpo, la variabile dell’ambito della funzione undefined è undefined (soprattutto prima del blocco) e si otterrà un’eccezione anche se si tenta di chiamarla.

Non sono sicuro da dove provenga la tua confusione. Secondo 10.2.1 è molto chiaro ciò che è o non è “in modalità rigorosa”. Nel vostro esempio, lo slot interno [[Strict]] foo s sarebbe effettivamente true e sarà in modalità rigorosa, ma il blocco che lo ospita non lo farà. La prima frase (quella che hai citato) si riferisce al blocco di hosting, non al contenuto generato al suo interno. Il blocco nel tuo frammento non è in modalità rigorosa e quindi quella sezione si applica ad esso.