Tipo di variabile di controllo Javascript. JavaScript, typeof, tipi e classi. Errori relativi alle zone morte temporanee

Identificazione dinamica del tipo

Identificazione dinamica del tipo (RTTI) consente di determinare il tipo di un oggetto durante l'esecuzione del programma. Risulta utile per una serie di motivi. In particolare, utilizzando un riferimento ad una classe base, è possibile determinare in modo abbastanza accurato il tipo di oggetto accessibile tramite questo riferimento. L'identificazione dinamica del tipo consente inoltre di verificare in anticipo il successo del cast del tipo, evitando un'eccezione dovuta a un cast del tipo errato. Inoltre, l'identificazione del tipo dinamico è una componente importante della riflessione.

Per supportare l'identificazione del tipo dinamico, C# ne fornisce tre parole chiave a: is, as e typeof. Ognuna di queste parole chiave viene discussa di seguito a turno.

è operatore

Il tipo specifico di un oggetto può essere determinato utilizzando l'operatore is. Di seguito è riportata la sua forma generale:

l'espressione è tipo

dove espressione denota una singola espressione che descrive l'oggetto il cui tipo viene testato. Se l'espressione è di tipo compatibile o uguale a quello sottoposto a test, il risultato di questa operazione è vero, altrimenti è falso. Pertanto, il risultato sarà vero se l'espressione ha un tipo testato in una forma o nell'altra. L'operatore is definisce entrambi i tipi come compatibili se sono dello stesso tipo o se viene fornita la conversione di riferimento, il boxing o l'unboxing.

Di seguito è riportato un esempio di utilizzo dell'operatore is:

Utilizzo del sistema; namespace ConsoleApplication1 ( class Add ( ) class Sum: Add ( ) class Program ( static void Main() ( Add a = new Add(); Sum s = new Sum(); if (a è Add) Console.WriteLine("Variabile a è di tipo Add"); if (s is Sum) Console.WriteLine("Il tipo di variabile s è ereditato dalla classe Add"); Console.ReadLine(); ) ) )

Operatore come

A volte si desidera eseguire una conversione del tipo in fase di esecuzione, ma non generare un'eccezione se la conversione fallisce, il che è del tutto possibile con il cast del tipo. L'operatore as serve a questo scopo, avendo la seguente forma generale:

espressione come tipo

dove espressione indica una singola espressione che converte nel tipo specificato.

Se il risultato di tale conversione ha esito positivo, viene restituito un riferimento al tipo, altrimenti un riferimento vuoto. L'operatore as può essere utilizzato solo per conversione di riferimento, identità, boxing, unboxing. In alcuni casi, l'operatore as può essere una comoda alternativa all'operatore is. Ad esempio, consideriamo il seguente programma:

Utilizzo del sistema; namespace ConsoleApplication1 ( class Add ( ) class Sum: Add ( ) class Program ( static void Main() ( Add a = new Add(); Sum s = new Sum(); // Esegue il casting del tipo a = s as Add; if (a != null) Console.WriteLine("Conversione riuscita"); else Console.WriteLine("Errore durante la conversione" Console.ReadLine() ) )

Il risultato dell'esecuzione di questo programma sarà una conversione riuscita.

  • Indefinito: "indefinito"
  • Nullo: "oggetto"
  • Booleano: "booleano"
  • Numero: "numero"
  • Stringa: "stringa"
  • Funzione: "funzione"
  • Tutto il resto: "oggetto"

A questa tabella vanno aggiunte le seguenti note:

1. typeof null === "oggetto" .

Teoricamente, qui c'è un punto sottile. Nei linguaggi tipizzati staticamente, una variabile di tipo oggetto non può contenere un oggetto (puntatore NULL, nil, null).

In pratica, questo è scomodo in JavaScript. Quindi gli sviluppatori di ES 5.1 faranno qualcosa di più intuitivo: typeof null === "null" .

Ma poiché abbiamo ancora ES3 ovunque, non sbagliatevi, ad esempio, con questo:

/* La funzione cerca qualche oggetto e lo restituisce oppure null se non viene trovato nulla */ function search() () var obj = search(); if (typeof obj === "object") ( // abbiamo davvero trovato l'oggetto (FAIL) obj.method(); )

2. Non dimenticare gli oggetti wrapper (tipo di nuovo Numero (5) === “oggetto”).

3. E non dimenticare il diritto dei browser di fare ciò che vogliono con gli oggetti host.

Non sorprenderti se Safari considera ostinatamente HTMLCollection un tipo di funzione e IE prima della versione 9 mantiene la nostra funzione alert() preferita come oggetto. Inoltre, Chrome considerava RegExp una funzione , ma ora sembra essere tornato in sé e risponde con object .

aString()

Cercare di scoprire il tipo di un valore dal risultato del suo metodo toString() è inutile. In tutte le “classi” questo metodo viene sovrascritto al proprio.

Il metodo è utile per visualizzare le informazioni di debug, ma non può essere utilizzato per determinare il tipo di una variabile.

Object.prototype.toString()

Sebbene toString venga sovrascritto all'interno di "classi" specifiche, abbiamo ancora la sua implementazione originale da Object. Proviamo ad usarlo:

console.log(Object.prototype.toString.call(valore));

console.log(Object.prototype.toString.call(valore));


Clinton alleggerisce questa noia

Stranamente, questo metodo funziona sorprendentemente bene.

Per i tipi scalari, restituisce , , , .

La cosa divertente è che anche il new Number(5) su cui typeof ha fallito qui ritorna .

Il metodo fallisce su null e non definito. Ritornano browser diversi, a volte previsti e a volte, a volte in generale. Tuttavia, puoi facilmente determinare il tipo di questi due valori senza questo.

Le cose si fanno interessanti quando arriviamo agli oggetti (quelli con typeof === "oggetto").

gli oggetti integrati funzionano praticamente alla grande:

  • {} —
  • Data -
  • Errore:
  • Espressione regolare —

L'unica cosa è che non rientra nell'elenco degli argomenti, ovvero .
Le cose stanno peggiorando di nuovo con gli oggetti host.

In IE, gli oggetti DOM hanno cominciato a diventare oggetti “normali” solo a partire dalla versione 8, e anche allora non del tutto. Pertanto, in IE 6-8, tutti questi oggetti (HTMLCOllection, DOMElement, TextNode, nonché documento e finestra) vengono semplicemente ridotti a file .

In tutti gli altri browser (incluso IE9), puoi già fare qualcosa con il risultato di toString. Anche se tutto non è facile: allora c'è HTMLCollection . finestra - poi, poi, poi. Ma puoi già provare a trarne qualcosa.

È più complicato con DOMElement: viene visualizzato nel modulo, - un formato diverso per ciascun tag. Ma anche qui la stagione regolare ci aiuterà.

La storia è più o meno la stessa con altri oggetti host (nei test di posizione e navigatore). Ovunque tranne IE, possono essere identificati dalla linea.

Svantaggi dell'utilizzo di Object.prototype.toString():

1. Questa possibilità non è coperta dalla norma. E qui dovremmo piuttosto rallegrarci che tutto funzioni così bene, piuttosto che lamentarci di alcune carenze.

2. Determinare un tipo analizzando una stringa restituita da un metodo che non viene utilizzato affatto per determinare un tipo, e viene anche chiamato su un oggetto a cui non si applica, lascia un sedimento nell'anima.

3. Nel vecchio IE, come puoi vedere, è normale non identificare gli oggetti host.

Tuttavia, questa è una cosa completamente funzionante se usata insieme ad altri mezzi.


Costruttori

E infine, i designer. Chi meglio dire della "classe" di un oggetto in JS rispetto al suo costruttore?

null e unfine non hanno né oggetti wrapper né costruttori.

Altri tipi scalari hanno wrapper, quindi puoi anche ottenere un costruttore:

(5).costruttore === Numero;

(Numero .NaN ) .costruttore === Numero ;

Ma exampleof non funzionerà qui:

5 istanza di Numero;

// false Numero .NaN istanza di Numero ;

// false true istanza di Boolean;

// false "string" istanza di String ;

// falso

5 istanza di Numero; // false Numero.NaN istanza di Numero; // false true istanza di Boolean; // false "string" istanza di String; // falso

(l'istanza funzionerà per il nuovo Numero(5) che soffre da lungo tempo)

Con le funzioni (che sono anche oggetti) exampleof funzionerà:

console.log ((funzione () ()) istanza della funzione);

// true console.log ( (funzione () ( ) ).costruttore === Funzione ) ;

// VERO

console.log((funzione () ()) istanza della funzione); // true console.log((funzione () ()).costruttore === Funzione); // VERO

Tutti gli oggetti delle classi integrate sono facilmente identificabili anche dai loro costruttori: Array, Date, RegExp, Error.

Qui sorge un problema con gli argomenti, il cui costruttore è Object.

E il secondo riguarda Object stesso, o meglio, come assegnargli un oggetto creato tramite un costruttore personalizzato.

In questo modo puoi definire solo l'oggetto base: obj istanza dell'Oggetto; Una delle opzioni di definizione è quella di passare attraverso tutti gli altri tipi possibili (Array, Error...) e se nessuno di essi si adatta - "oggetto".

Costruttori e oggetti host

Le cose peggiorano con gli oggetti host.

Partiamo dal fatto che IE fino alla versione 7 inclusa non li considera affatto oggetti normali. Semplicemente non hanno designer e prototipi lì (in ogni caso un programmatore non può raggiungerli).

Le cose vanno meglio in altri browser. Esistono costruttori e puoi usarli per determinare la classe di un valore. Vengono solo convocati

browser diversi

diversamente. Ad esempio, per HTMLCollection il costruttore sarà HTMLCollection o NodeList o anche NodeListConstructor.
Dovresti anche definire un costruttore di base per DOMElement. In FF, questo è, ad esempio, HTMLElement , da cui HTMLDivElement e altri già ereditano.
Il trucco viene lanciato a FireFox sotto la versione 10 e Opera sotto la 11. Il costruttore della raccolta è Object .
nome.costruttore

I costruttori hanno anche una proprietà name, che può essere utile.

Nessuno dei metodi presentati fornisce una determinazione al 100% del tipo/classe di un valore in tutti i browser. Tuttavia, nel loro insieme, essi consentono di farlo.

Nel prossimo futuro cercherò di raccogliere tutti i dati in tabelle e fornire un esempio di funzione di definizione.

JavaScript O JS(abbreviato) non è un linguaggio facile e gli sviluppatori alle prime armi non lo impareranno subito. All'inizio imparano le basi e tutto sembra colorato e bello. Andando un po' più in profondità, appaiono array JavaScript, oggetti, callback e tutto ciò che è simile, il che spesso ti lascia a bocca aperta.

In JavaScript è importante verificare correttamente il tipo di variabile. Diciamo che vuoi sapere se una variabile è un array o un oggetto? Come verificarlo correttamente? In questo caso particolare, ci sono dei trucchi durante la verifica e questo post ne parlerà. Cominciamo subito.

Verifica del tipo di una variabile

Ad esempio, devi verificare se una variabile è un oggetto, un array, una stringa o un numero. Puoi usare typeof per questo, ma non sempre dirà la verità e nell'esempio seguente mostrerò il perché.

Ho scritto questo esempio per mostrare chiaramente perché typeof non è sempre la scelta giusta.

Var_comparison = (string: "string", int: 99, float: 13.555, oggetto: (ciao: "ciao"), array: new Array(1, 2, 3) ); // Restituisce un array con le chiavi dell'oggetto var _objKeys = Object.keys(_comparison); for(var i = 0; i<= _objKeys.length - 1; i++) { // выведем в консоль тип каждой переменной console.log(typeof _comparson[_objKeys[i]]); }

Risultato dell'esecuzione del codice:

Oggetto numero stringa numero oggetto

Giusto? - Ovviamente no. Ci sono due problemi. Ciascuno di essi verrà descritto in dettaglio e verrà proposta una soluzione.

Primo problema: numero float, output come numero

Comparison.float non è un numero e invece del numero dovrebbe essere un float (numero in virgola mobile). Per risolvere questo problema, puoi creare una funzione con un controllo come nel codice seguente.

Var_floatNumero = 9,22; var _notFloatNumber = 9; console.log(isFloat(_floatNumber)); console.log(isFloat(_notFloatNumber)); console.log(isFloat("")); funzione èMobile(n)( return Numero(n) === n && n % 1 !== 0; )

La funzione isFloat() verifica che tutti i valori siano in virgola mobile. Innanzitutto viene verificato se la variabile è uguale a N numero (Number(n) === n) e se sì, viene effettuato un altro controllo per la divisione con resto e se c'è un resto, allora un valore booleano ( VERO O falso) risultato (n % 1 !== 0).

Nell'esempio sopra ritorna VERO, falso E falso. Il primo significato è galleggiante tipo, il secondo no: è un numero normale e l'ultimo è solo una stringa vuota che non soddisfa le regole.

Secondo problema: l'array era definito come oggetto

Nel primo esempio, l'array veniva visualizzato come oggetto e questo non è molto positivo, poiché a volte è necessario utilizzare esattamente questo tipo e nient'altro.

Esistono diversi modi per verificare se una variabile è di tipo array.

Prima opzione (buona opzione). Controlliamo se i dati appartengono a un array utilizzando istanzaof().

Dati Var = new Array("ciao", "mondo"); var isArr = istanza dati dell'array;

Seconda opzione (buona opzione). Il metodo Array.isArray() restituisce un valore booleano che dipenderà dal fatto che la variabile sia o meno un array ().

Dati Var = new Array("ciao", "mondo"); var isArr = Array.isArray(dati);

Terza opzione (la migliore, ma lunga). Per comodità, puoi rendere questo metodo una funzione. Usando Object facciamo . Se il risultato di Object.prototype.toString.call(data) non è uguale, la variabile non è un array ().

Dati Var = new Array("ciao", "mondo"); var isArr = Object.prototype.toString.call(data) == ""; console.log(isArr);

L'ultimo risultato sotto forma di funzione di convenienza:

Funzione isArray(dati) ( return Object.prototype.toString.call(data) == "" )

Ora puoi chiamare le funzioni isArray() e impostare un array o qualcos'altro come argomento e vedere il risultato.

Postfazione

La registrazione si è rivelata piuttosto grande di quanto originariamente previsto. Ma ne sono soddisfatto perché descrive in modo abbastanza conciso e chiaro le difficoltà durante il controllo delle variabili in JavaScript e come aggirarle.

Se hai ancora domande, scrivile qui sotto a questa voce. Sarò felice di aiutarti.

a = (b > 0) && (c + 1 != d); bandiera =!(stato = 0);

Tabella 14.5. Operatori logici

Descrizione dell'operatore

! NOT (inversione logica)

&& AND (moltiplicazione logica)

|| OR (addizione logica)

Tabella 14.6. Risultati dell'esecuzione degli operatori AND e OR

Operando 1

Operando 2

Tabella 14.7. Risultati dell'esecuzione dell'operatore NOT

Ricevi operatore tipodi

Digitare l'operatore get typeof restituisce una stringa che descrive il tipo di dati dell'operando. L'operando di cui vuoi conoscere il tipo viene posizionato dopo questo operatore e racchiuso tra parentesi:

s = tipodi("str");

Come risultato dell'esecuzione di questa espressione, la variabile s conterrà la stringa "string" che indica il tipo di stringa.

Tutti i valori che l'operatore typeof può restituire sono elencati nella tabella. 14.8.

Tabella 14.8. Valori restituiti dall'operatore typeof

Tipo di dati

Stringa di ritorno

Corda

Numerico

Tabella 14.8 (fine)

Tipo di dati

Stringa di ritorno

Logico

Compatibilità e conversione dei tipi di dati

È tempo di considerare due questioni più importanti: compatibilità dei tipi di dati e conversione da un tipo all'altro.

Cosa ottieni quando aggiungi due valori numerici? Esatto, un altro valore numerico. Cosa succede se aggiungi un numero e una stringa? È difficile da dire... Qui JavaScript affronta il problema dei tipi di dati incompatibili e cerca di rendere compatibili questi tipi convertendone uno in un altro. Innanzitutto tenta di convertire la stringa in un numero e, in caso di successo, esegue un'addizione. In caso di esito negativo, il numero verrà convertito in una stringa e le due stringhe risultanti verranno concatenate. Ad esempio, l'esecuzione dello script Web nel Listato 14.6 convertirebbe il valore di b in un valore numerico quando aggiunto ad a; quindi la variabile c conterrà il valore 23.

Listato 14.6

var a, b, c, d, e, f; un = 11;

b = "12"; c = a+b;

d = "JavaScript"; e = 2;

Ma poiché il valore della variabile d non può essere convertito in un numero, il valore di e verrà convertito in una stringa e il risultato - il valore di f - diventerà uguale a

I valori booleani vengono convertiti in valori numerici o stringa, a seconda del caso specifico. Il valore true verrà convertito nel numero 1 o nella stringa "1" e il valore false verrà convertito in 0 o "0" . Al contrario, il numero 1 verrà convertito in true e il numero 0 verrà convertito in false . Inoltre, verrà convertito in false

Abbiamo i valori null e indefiniti.

Parte III. Comportamento della pagina web. Script Web

Si può vedere che JavaScript fatica a eseguire correttamente anche le espressioni scritte male. A volte funziona, ma il più delle volte non tutto funziona come previsto e, alla fine, l'esecuzione dello script Web viene interrotta a causa del rilevamento di un errore in un posto completamente diverso, su un'istruzione assolutamente corretta. Pertanto, è meglio evitare tali incidenti.

Precedenza degli operatori

L'ultimo problema che esamineremo qui è la precedenza degli operatori. Come ricordiamo, la precedenza influisce sull'ordine in cui vengono eseguiti gli operatori in un'espressione.

Sia la seguente espressione:

In questo caso, prima verrà aggiunto il valore di c al valore della variabile b, quindi dalla somma verrà sottratto 10. Gli operatori di questa espressione hanno la stessa priorità e quindi vengono eseguiti rigorosamente da sinistra a destra.

Consideriamo ora questa espressione:

Qui il valore c verrà prima moltiplicato per 10 e solo successivamente al prodotto risultante verrà aggiunto il valore b. L'operatore di moltiplicazione ha una precedenza maggiore rispetto all'operatore di addizione, quindi l'ordine "rigorosamente da sinistra a destra" verrà interrotto.

Gli operatori di assegnazione hanno la priorità più bassa. Ecco perché viene valutata prima l'espressione stessa e poi il suo risultato viene assegnato a una variabile.

IN In generale, il principio di base per l'esecuzione di tutti gli operatori è il seguente: vengono eseguiti prima gli operatori con una priorità più alta e solo dopo quelli con una priorità più bassa. Gli operatori con la stessa priorità vengono eseguiti nell'ordine in cui appaiono (da sinistra a destra).

IN tavolo 14.9 elenca tutti gli operatori da noi studiati in ordine decrescente di priorità.

Tabella 14.9. Precedenza degli operatori (in ordine decrescente)

Operatori

Descrizione

++ -- - ~ ! tipodi

Incremento, decremento, cambio di segno, NOT logico, definizione del tipo

Moltiplicazione, divisione, resto

Addizione e concatenazione di stringhe, sottrazione

Operatori di confronto

AND logico

Capitolo 14. Introduzione alla programmazione Web. Linguaggio JavaScript

Tabella 14.9 (fine)

Operatori

Descrizione

OR logico

Operatore condizionale(vedi sotto)

= <оператор>=

Compito, semplice e complesso

ATTENZIONE!

Ricorda questa tabella. L'esecuzione impropria di istruzioni può causare errori difficili da individuare, in cui un'espressione apparentemente assolutamente corretta produce un risultato errato.

Ma cosa succede se dobbiamo interrompere il normale ordine di esecuzione delle istruzioni? Usiamo le parentesi. Se scritte in questo modo, le istruzioni racchiuse tra parentesi vengono eseguite per prime:

a = (b + c) * 10;

Qui verranno prima sommati i valori delle variabili b e c, quindi la somma risultante verrà moltiplicata per 10.

Anche gli operatori racchiusi tra parentesi sono soggetti a precedenza. Questo è il motivo per cui vengono spesso utilizzate più parentesi nidificate:

a = ((b + c) * 10 - d) / 2 + 9;

Qui gli operatori verranno eseguiti nella seguente sequenza:

1. Aggiunta di b e c.

2. Moltiplicare l'importo risultante per 10.

3. Sottrarre d dal prodotto.

4. Dividi la differenza per 2.

5. Aggiungendo 9 al quoziente.

Se rimuovi le parentesi:

a = b+c*10 - d/2+9;

quindi l’ordine di esecuzione degli operatori sarà il seguente:

1. Moltiplicare c e 10.

2. Dividi per 2.

3. Addizione di b e prodotto di c e 10.

4. Sottrarre il quoziente della divisione dalla somma risultante d per 2.

5. Aggiungi 9 alla differenza risultante.

Si scopre un risultato completamente diverso, non è vero?