Următoarele note ar trebui adăugate la acest tabel:
1. typeof null === „obiect” .
Teoretic, există un punct subtil aici. În limbajele tipizate static, o variabilă de tip obiect nu poate conține un obiect (NULL, nil, pointer nul).
În practică, acest lucru este incomod în JavaScript. Deci, dezvoltatorii ES 5.1 vor face ceva mai intuitiv: typeof null === "null" .
Dar, din moment ce încă avem ES3 peste tot, nu vă înșelați, de exemplu, cu asta:
/* Funcția caută un obiect și îl returnează sau null dacă nu se găsește nimic */ function search() () var obj = search(); if (typeof obj === „obiect”) ( // am găsit cu adevărat obiectul (FAIL) obj.method(); )
2. Nu uitați de obiectele de înveliș (typeof new Number(5) === „obiect”).
3. Și nu uitați de dreptul browserelor de a face tot ce doresc cu obiectele gazdă.
Nu fi surprins că Safari consideră că HTMLCollection este un tip de funcție, iar IE, mai devreme decât versiunea 9, păstrează funcția noastră favorită alert() ca obiect. De asemenea, Chrome obișnuia să considere RegExp o funcție, dar acum pare să-și vină în fire și să îi răspundă cu obiect.
Încercarea de a afla tipul unei valori din rezultatul metodei sale toString() este inutilă. În toate „clasele” această metodă este înlocuită cu propria ei.
Metoda este bună pentru afișarea informațiilor de depanare, dar nu poate fi folosită pentru a determina tipul unei variabile.
Deși toString este suprascris în anumite „clase”, încă avem implementarea sa inițială din Object. Să încercăm să-l folosim:
console.log(Object.prototype.toString.call(valoare)); |
console.log(Object.prototype.toString.call(valoare));
Clinton ușurează această oboseală
Destul de ciudat, această metodă funcționează surprinzător de bine.
Pentru tipurile scalare, returnează , , , .
Lucrul amuzant este că chiar și noul Number(5) la care tip de eșuat aici revine .
Metoda eșuează pe null și nedefinit. Se întorc diferite browsere, uneori de așteptat și alteori, uneori în general. Cu toate acestea, puteți determina cu ușurință tipul acestor două valori fără acest lucru.
Lucrurile devin interesante când ajungem la obiecte (cele cu typeof === „obiect”).
obiectele încorporate funcționează practic cu un bang:
Singurul lucru este că iese din lista de argumente, care este fie .
Lucrurile se înrăutățesc din nou cu obiectele gazdă.
În IE, obiectele DOM au început să devină obiecte „normale” doar din versiunea 8 și chiar și atunci nu complet. Prin urmare, în IE 6-8, toate aceste obiecte (HTMLCOllection, DOMElement, TextNode, precum și document și window) sunt pur și simplu reduse la .
În toate celelalte browsere (inclusiv IE9), puteți deja să faceți ceva cu rezultatul toString. Deși totul nu este, de asemenea, ușor: HTMLCollection este acolo, atunci . fereastra - apoi, apoi, atunci. Dar poți încerca deja să scoți ceva din asta.
Este mai complicat cu DOMElement: este afișat sub formă, - un format diferit pentru fiecare etichetă. Dar sezonul regulat ne va ajuta și aici.
Povestea este aproximativ aceeași cu alte obiecte gazdă (în testele de locație și navigator). Peste tot, cu excepția IE, ele pot fi identificate prin linie.
Dezavantaje ale utilizării Object.prototype.toString():
1. Această posibilitate nu este acoperită de standard. Și aici ar trebui să ne bucurăm mai degrabă că totul funcționează atât de bine, decât să ne plângem de unele dintre deficiențe.
2. Determinarea unui tip prin parsarea unui șir returnat printr-o metodă care nu este folosită deloc pentru a determina un tip și este, de asemenea, apelată la un obiect la care nu se raportează, lasă niște sedimente în suflet.
3. În vechiul IE, după cum puteți vedea, este normal să nu identificați obiectele gazdă.
Cu toate acestea, acesta este un lucru complet funcțional atunci când este utilizat împreună cu alte mijloace.
Și în sfârșit, designerii. Cine poate spune mai bine despre „clasa” unui obiect în JS decât constructorul său?
null și nedefinit nu au nici obiecte wrapper, nici constructori.
Alte tipuri scalare au wrapper-uri, așa că puteți obține și un constructor:
(5).constructor === Număr; |
(Număr .NaN ) .constructor === Număr ;
(adevărat).constructor === Boolean;
("șir" ) .constructor === String ; |
5 instanță de Număr; // false Number.NaN instanceof Number; // false adevărată instanță booleană; // "șir" fals instanță de șir; // fals
(instanceof va funcționa pentru noul îndelungat număr (5))
Cu funcții (care sunt și obiecte) instanceof va funcționa:
console.log ( (funcție () ( ) ) instanceof Funcție); |
// true console.log ( (funcție () ( ) ).constructor === Funcție ) ;
// adevărat
console.log((funcția () ()) instanceof Funcție); // true console.log((function () ()).constructor === Function); // adevărat
Toate obiectele claselor încorporate sunt de asemenea ușor identificate de către constructorii lor: Array, Date, RegExp, Error.
O problemă apare aici cu argumentele, al căror constructor este Object.
Și al doilea este cu Object în sine, sau mai degrabă, cum să îi atribui un obiect creat printr-un constructor personalizat.
Astfel, puteți defini doar obiectul de bază:
Una dintre opțiunile de definire este să parcurgeți toate celelalte tipuri posibile (Matrice, Eroare...) și dacă niciunul nu se potrivește - „obiect”.
Constructori și obiecte gazdă
Lucrurile se înrăutățesc cu obiectele gazdă.
Să începem cu faptul că IE până la versiunea 7 inclusiv nu le consideră deloc obiecte normale. Pur și simplu nu au designeri și prototipuri acolo (în orice caz, un programator nu poate ajunge la ei).
Lucrurile sunt mai bune în alte browsere. Există constructori și îi puteți folosi pentru a determina clasa unei valori. Pur și simplu sunt numite diferit în browsere diferite. De exemplu, pentru HTMLCollection, constructorul va fi fie HTMLCollection, fie NodeList, fie chiar NodeListConstructor.
Trucul este aruncat la FireFox sub versiunea 10 și Opera sub 11. Constructorul colecției de acolo este Object .
constructor.nume
Constructorii au și o proprietate de nume, care poate fi utilă.
Conține numele funcției de constructor, de exemplu, (5).constructor.name === „Număr” .
Cu toate acestea:
1. Nu există deloc în IE, nici măcar în 9.
3. argumente din nou „obiect”.
Concluzii
Niciuna dintre metodele prezentate nu oferă o determinare 100% a tipului/clasei unei valori în toate browserele. Cu toate acestea, luate împreună, fac posibil acest lucru. În viitorul apropiat voi încerca să colectez toate datele în tabele și să dau un exemplu de funcție de definire. returnează un șir care indică tipul operandului.
Operandul urmează tipul operatorului:
Tip de operand
operand este o expresie care reprezintă un obiect sau o primitivă al cărui tip urmează să fie returnat.
Următorul tabel listează valorile posibile de returnare ale tipului de. Mai multe informații despre tipuri și primitive pot fi găsite pe pagină.
În prima implementare a JavaScript, valorile erau reprezentate de un tip de etichetă și o pereche de valori. Tipul de etichetă pentru obiecte a fost 0. null a fost reprezentat ca un pointer nul (0x00 pe majoritatea platformelor). Prin urmare, tipul de etichetă pentru null a fost nul, deci valoarea returnată a tipului de este inactivă. ()
O remediere a fost propusă în ECMAScript (prin dezactivare), dar a fost respinsă. Acest lucru ar avea ca rezultat tipul null === „null” .
Expresiile regulate apelabile au fost o adăugare non-standard în unele browsere.
Tipul /s/ === „funcție”; // Chrome 1-12 nu respectă tipul ECMAScript 5.1 de /s/ === „obiect”; // Firefox 5+ Respectă ECMAScript 5.1
Înainte de ECMAScript 2015, operatorul typeof era garantat să returneze un șir pentru orice operand cu care a fost apelat. Acest lucru s-a schimbat odată cu adăugarea declarațiilor let și const fără ridicare în bloc. Acum, dacă variabilele sunt declarate cu let și const și typeof este apelat pe ele în blocul de declarare a variabilelor, dar înainte de declarație, atunci este aruncată o ReferenceError. Comportamentul diferă de variabilele nedeclarate, pentru care typeof va returna „nedefinit”. Variabilele blocate au o „zonă moartă temporară” care durează de la începutul blocului până când variabila este declarată. În această zonă, o încercare de a accesa variabile aruncă o excepție.
Typeof undeclaredVariable === „nedefinit”; typeof newLetVariable; let newLetVariable; // ReferenceError typeof newConstVariable; const newConstVariable = "bună ziua"; // ReferenceError
În toate browserele curente, există un obiect gazdă non-standard document.all, care este de tipul Undefined.
Tipul documentului.all === „nedefinit”;
Deși specificația permite nume de tip personalizate pentru obiecte exotice non-standard, necesită ca aceste nume să fie diferite de cele predefinite. Situația în care document.all este de tip nedefinit ar trebui considerată o încălcare excepțională a regulilor.
Caietul de sarcini | Stare | Comentarii |
---|---|---|
Ultima versiune ECMAScript (ECMA-262) |
Proiect | |
ECMAScript 2015 (ediția a 6-a, ECMA-262) Definiția „Tipului de operator” este în această specificație. |
Standard | |
ECMAScript 5.1 (ECMA-262) Definiția „Tipului de operator” este în această specificație. |
Standard | |
ECMAScript ediția a treia (ECMA-262) Definiția „Tipului de operator” este în această specificație. |
Standard | |
ECMAScript prima ediție (ECMA-262) Definiția „Tipului de operator” este în această specificație. |
Standard | Definiție inițială. Implementat în JavaScript 1.1 |
Actualizați datele de compatibilitate pe GitHub
Calculatoare | Mobil | Server | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Chrome | Margine | Firefox | Internet Explorer | Operă | Safari | Vizualizare web Android | Chrome pentru Android | Firefox pentru Android | Opera pentru Android | Safari pe iOS | Samsung Internet | Node.js | |
În viitorul apropiat voi încerca să colectez toate datele în tabele și să dau un exemplu de funcție de definire. | Chrome Sprijin deplin 1 | Margine Sprijin deplin 12 | Firefox Sprijin deplin 1 | I.E. Sprijin deplin 3 | Operă Sprijin deplin Da | Safari Sprijin deplin Da | WebView Android Sprijin deplin 1 | Chrome Android Sprijin deplin 18 | Firefox Android Sprijin deplin 4 | Opera Android Sprijin deplin Da | Safari iOS Sprijin deplin Da | Samsung Internet Android Sprijin deplin 1.0 | nodejs Sprijin deplin Da |
În IE 6, 7 și 8, multe obiecte gazdă sunt obiecte, dar nu funcții. De exemplu.
JavaScript sau JS(abreviat) nu este un limbaj ușor și dezvoltatorii începători nu vor afla despre el imediat. La început învață elementele de bază și totul pare colorat și frumos. Mergând un pic mai adânc, apar matrice JavaScript, obiecte, apeluri inverse și orice altceva de genul ăsta, ceea ce de multe ori vă surprinde mintea.
În JavaScript, este important să verificați corect tipul unei variabile. Să presupunem că vrei să știi dacă o variabilă este o matrice sau un obiect? Cum să verific asta corect? În acest caz particular, există trucuri în timpul verificării și această postare va fi despre ele. Să începem imediat.
De exemplu, trebuie să verificați dacă o variabilă este un obiect, o matrice, un șir sau un număr. Puteți folosi typeof pentru aceasta, dar nu va spune întotdeauna adevărul și în exemplul de mai jos voi arăta de ce.
Am scris acest exemplu pentru a arăta clar de ce typeof nu este întotdeauna alegerea potrivită.
Var _comparație = ( șir: „șir”, int: 99, float: 13.555, obiect: (bună ziua: „bună ziua”), matrice: nou Array(1, 2, 3) ); // Returnează o matrice cu cheile obiectului var _objKeys = Object.keys(_comparison); pentru(var i = 0; i<= _objKeys.length - 1; i++) { // выведем в консоль тип каждой переменной console.log(typeof _comparson[_objKeys[i]]); }
Rezultatul executării codului:
șir număr număr obiect obiect
Corect? - Desigur că nu. Sunt două probleme. Fiecare dintre ele va fi descrisă în detaliu și va fi propusă o soluție.
Prima problemă: număr flotant, ieșire ca număr
Comparison.float nu este un număr și în loc de număr ar trebui să fie un float (număr în virgulă mobilă) Pentru a remedia acest lucru, puteți crea o funcție cu o verificare ca în codul de mai jos.
Var_floatNumber = 9,22; var _notFloatNumber = 9; console.log(isFloat(_floatNumber)); console.log(isFloat(_notFloatNumber)); console.log(isFloat("")); funcția isFloat(n)( returnează Număr(n) === n && n % 1 !== 0; )
Funcția isFloat() verifică dacă toate valorile sunt în virgulă mobilă. În primul rând, se verifică dacă variabila este egală cu n număr (Număr(n) === n) și dacă da, se face o altă verificare pentru împărțirea cu rest și dacă există un rest, atunci un boolean ( adevărat sau fals) rezultat (n % 1 !== 0).
În exemplul de mai sus revine adevărat, falsŞi fals. Primul sens este plutire tip, al doilea nu este - este un număr obișnuit, iar ultimul este doar un șir gol care nu se potrivește cu regulile.
A doua problemă: matricea a fost definită ca obiect
În primul exemplu, matricea a fost afișată ca obiect și acest lucru nu este foarte bun, deoarece uneori trebuie să utilizați exact acest tip și nimic altceva.
Există mai multe moduri de a verifica dacă o variabilă este de tip matrice.
Prima opțiune (opțiune bună). Verificăm dacă datele aparțin unui tablou folosind instanceof().
Var date = new Array ("bună ziua", "lumea"); var isArr = data instanceof Array;
A doua opțiune (opțiune bună). Metoda Array.isArray() returnează o valoare booleană care va depinde dacă variabila este o matrice sau nu ().
Var date = new Array ("bună ziua", "lumea"); var isArr = Array.isArray(data);
A treia opțiune (cea mai bună, dar lungă). Pentru comoditate, puteți face din această metodă o funcție. Folosind Object facem . Dacă rezultatul Object.prototype.toString.call(data) nu este egal, atunci variabila nu este o matrice ().
Var date = new Array ("bună ziua", "lumea"); var isArr = Object.prototype.toString.call(data) == ""; console.log(isArr);
Ultimul rezultat sub forma unei funcții de confort:
Funcția isArray(data) ( return Object.prototype.toString.call(data) == "" )
Acum puteți apela funcțiile isArray() și puteți seta o matrice sau altceva ca argument și să vedeți rezultatul.
Înregistrarea s-a dovedit a fi destul de mare decât era prevăzut inițial. Dar sunt mulțumit de el, deoarece descrie destul de succint și clar dificultățile la verificarea variabilelor în JavaScript și cum să le ocoliți.
Dacă mai aveți întrebări, scrieți-le mai jos la această intrare. Voi fi bucuros să vă ajut.
Identificarea dinamică a tipului
Identificare dinamică a tipului (RTTI) vă permite să determinați tipul unui obiect în timpul execuției programului. Se dovedește a fi util din mai multe motive. În special, folosind o referință la o clasă de bază, puteți determina destul de precis tipul de obiect accesibil prin această referință. Identificarea dinamică a tipului vă permite, de asemenea, să verificați în prealabil cât de reușită va avea o distribuție de tip, prevenind o excepție din cauza unui tip incorect. În plus, identificarea tipului dinamic este o componentă majoră a reflecției.
Pentru a sprijini identificarea dinamică a tipului, C# oferă trei cuvinte cheie: is, as, și typeof. Fiecare dintre aceste cuvinte cheie este discutat mai jos pe rând.
Tipul specific al unui obiect poate fi determinat folosind operatorul is. Mai jos este forma sa generală:
expresia este tip
unde expresie denotă o singură expresie care descrie obiectul al cărui tip este testat. Dacă expresia este compatibilă sau de același tip cu tipul testat, atunci rezultatul acestei operații este adevărat, în caz contrar este fals. Astfel, rezultatul va fi adevărat dacă expresia are un tip testat într-o formă sau alta. Operatorul is definește ambele tipuri ca fiind compatibile dacă sunt de același tip sau dacă sunt furnizate conversie de referință, boxing sau unboxing.
Mai jos este un exemplu de utilizare a operatorului is:
Utilizarea sistemului; namespace ConsoleApplication1 ( clasa Add ( ) class Sum: Add ( ) class Program ( static void Main() ( Add a = new Add(); Sum s = new Sum(); if (a este Add) Console.WriteLine("Variable a este de tip Add"); dacă (s este Sum) Console.WriteLine("Tipul variabilei s este moștenit de la clasa Add"); Console.ReadLine(); ) ) )
Uneori doriți să efectuați o conversie de tip în timpul execuției, dar nu să aruncați o excepție dacă conversia nu reușește, ceea ce este foarte posibil cu turnarea de tip. Operatorul în calitate servește acestui scop, având următoarea formă generală:
expresie ca tip
unde expresie denotă o singură expresie care se convertește la tipul specificat.
Dacă rezultatul unei astfel de conversii este de succes, atunci se returnează o referință la tip, în caz contrar o referință goală. Operatorul as poate fi folosit doar pentru conversie de referință, identitate, boxing, unboxing. În unele cazuri, operatorul as poate servi ca o alternativă convenabilă la operatorul is. Ca exemplu, luați în considerare următorul program:
Utilizarea sistemului; namespace ConsoleApplication1 ( class Add ( ) class Sum: Add ( ) class Program ( static void Main() ( Add a = new Add(); Sum s = new Sum(); // Efectuați casting tip a = s ca Add; dacă (a != null) Console.WriteLine("Conversia a avut succes"); else Console.WriteLine("Eroare în timpul conversiei");
Rezultatul executării acestui program va fi o conversie reușită.