Classi ES6: che dire dell’ospedale?

In ES5, potrei verificare l’esistenza di una “class” (funzione di costruzione) sull’object della finestra:

if (window.MyClass) { ... // do something } 

In ES6, secondo questo articolo , le classi dichiarate globalmente sono globali, ma non proprietà dell’object globale ( window , sui browser):

Ma ora ci sono anche variabili globali che non sono proprietà dell’object globale. Nell’ambito globale, le seguenti dichiarazioni creano tali variabili:

  • let dichiarazioni
  • const dichiarazioni
  • Dichiarazioni di class

Quindi se non posso usare if (window.MyClass) , c’è un modo per fare lo stesso?

In realtà c’è un modo corretto per farlo senza usare l’object window?

In ES5, potremmo verificare l’esistenza di una class sull’object della finestra

Solo se la funzione di costruzione era globale, il che è una ctriggers pratica.

In ES6, secondo questo articolo , le classi dichiarate globalmente sono globali, ma non proprietà dell’object globale …

Corretta. (Lo stesso vale let dichiarazioni let e const a livello globale.) Questo è definito in §8.1.1.4: Record globali dell’ambiente :

Un record ambientale globale è logicamente un singolo record ma è specificato come un composito che incapsula un object Environment Record e un dichiarativo Record ambientale. L’object Record Ambiente ha come object base l’object globale del Reame associato. Questo object globale è il valore restituito dal metodo concreto GetThisBinding del record ambientale globale. (Ad esempio, l’object globale a cui fa riferimento la window sui browser – TJ) L’object Ambiente Record componente di un record ambientale globale contiene i collegamenti per tutti i globali incorporati (clausola 18) e tutti i binding introdotti da una FunctionDeclaration , GeneratorDeclaration o VariableStatement contenuta nel codice globale. I binding per tutte le altre dichiarazioni ECMAScript nel codice globale sono contenuti nel componente dichiarativo Record dell’ambiente del record ambientale globale.

(La mia enfasi) Quindi le cose che prima andavano sull’object globale in ES5 e in precedenza continuano (più i generatori, perché sarebbe stato ancora più confuso se non lo fossero), ma le cose nuove ( let , const , e dichiarazioni di class ) no . Sono globali, ma non proprietà dell’object globale.

Torna alla tua domanda …

Quindi se non posso usare if (window.MyClass) , c’è un modo per fare lo stesso?

Potresti usare

 if (typeof MyClass === "function") { 

… poiché typeof su un simbolo irrisolvibile non lancia un ReferenceError . Questo ha anche il vantaggio di verificare se MyClass rientra nel campo di applicazione del codice, anche se non è globale.

C’è però un trucco: se quel codice si trova nello stesso ambito in cui MyClass è dichiarato tramite class (o let o const ) ma è sopra MyClass in MyClass , anche il controllo typeof genererà un ReferenceError , perché non è ansible accedere al l’associazione crea tutto (nemmeno con typeof ) prima della class (o let o const ).

Ad esempio, questo getterà:

 if (typeof MyClass === "function") { // ReferenceError here // Yup, it's defined // ... } // ... class MyClass { } 

Lo spazio dall’inizio della portata alla class , let o const line viene chiamato zona morta temporanea (TDZ) e non è ansible accedere al binding della variabile. Di conseguenza, devi prendere l’errore ReferenceError :

 let exists = false; try { exists = typeof MyClass === "function"; } catch (e) { } 

In realtà c’è un modo corretto per farlo senza usare l’object window?

Fino a quando i moduli JavaScript non raggiungeranno il vasto supporto del browser, ci sono un paio di modi:

  1. Utilizzare una libreria di definizioni di moduli asincroni di qualche tipo per gestire il caricamento dei moduli. Alcuni esempi: RequireJS, SystemJS, CommonJS

  2. Avere un’unica variabile globale che utilizzerai per fare riferimento a un object e creare le varie proprietà globali dell’applicazione di tale object. Ecco un modo tipico per farlo:

     var MyApp = MyApp || {}; if (!MyApp.ThisModule) { // You can leave this `if` out // if there's no chance of the file // being loaded more than once MyApp.ThisModule = function(module) { module.MyClass = class MyClass { // ...class definition here... } }({}); } 

Questo ti dà anche un utile scope (la funzione anonima) in cui inserire qualsiasi globale a livello di modulo.