Ghidul începătorului de tip de constrângere un exemplu practic

De-a lungul acestei serii de articole, am vorbit despre tipul de coerciție, modul în care acesta diferă de conversia de tip și cum funcționează în limbi dinamice de tiparire.

Dacă tocmai vă alăturați seriei, consultați articolele anterioare pentru a vă asigura că vă grăbiți cu viteza în care ne aflăm acum:

  1. Tipuri de date
  2. Ce este coerciția de tip? 

În timp ce celălalt articol sa concentrat pe limbi slabe și pe tipuri de date la un nivel înalt, vom examina câteva exemple specifice de constrângere de tip într-o limbă slabă și capcanele pe care le putem experimenta fără să știm cum funcționează coerciția și cum poate să se întoarcă.

Mai precis, vom analiza mai multe exemple folosind JavaScript și deși rezultatele pe care le puteți vedea prin utilizarea exemplelor nu vor fi neapărat traduse 1: 1 în alte limbi, acestea vor furniza în continuare un set de teste pe care dvs. poate să efectueze în ceea ce utilizați în proiectele zilnice sau în partea dvs. și să evaluați rezultatele pe care le vedeți.

Regulile de comparare

În mod evident, una dintre problemele cele mai frecvente care apar în limbile slabe de scris vine ori de câte ori facem comparații. Sigur, există și alte momente în care se așteaptă ca o variabilă să fie un tip atunci când este cu adevărat altul care ne poate afecta negativ, dar problemele cele mai frecvente apar atunci când efectuăm un tip de comparație.

Aceste comparații pot veni sub forma operațiunilor de egalitate, operațiuni condiționate, operații bitrate sau în timpul comutator / caz operațiuni. 

După cum sa menționat în articolele anterioare din această serie, diferitele limbi au diferite moduri în care se referă la coerciționarea tipurilor de date, astfel încât exemplele la care ne uităm în acest articol pot să difere puțin în munca pe care o faceți. 

Adică, vom examina aceste exemple utilizând JavaScript, deoarece este o limbă folosită pe scară largă, dar regulile sunt încă aplicabile în alte limbi - este doar faptul că alte limbi pot plasa o prioritate diferită pe un tip de date față de altul rezultatele constrângerii pot fi puțin diferite.

Prin urmare, cu acest lucru, să începem să analizăm modul în care JavaScript gestionează comparațiile între tipurile de date utilizând operatorul de egalitate (==), operatorul strict de egalitate (===) și când se utilizează valori cum ar fi nedefinit și nul.

Nul și nedefinit

Înainte de a căuta comparații între diferite tipuri de date, hai să luăm o clipă pentru a reține că în JavaScript, nedefinit și nul sunt două tipuri diferite de valori. Ca și cum acest lucru nu este suficient, poate deveni și mai confuz când se compară cele două valori.

Mai întâi, rețineți următoarele:

  • Dacă trebuia să executați tipof (nedefinit) în consola, atunci rezultatul ar fi nedefinit.
  • Dacă ar fi fost executat tip (null) în consola, atunci rezultatul ar fi obiect.

Apoi, dacă ați declara o variabilă fără să-i atribuiți o valoare și ați evalua tipul ei, atunci ați vedea nedefinit.

/ ** * Declarați o variabilă 'name', dar nu o atribuiți unei valori. * Executați rezultatul "typeof" pe o consolă și veți primi * 'undefined'. * / var name; tip (nume);

Apoi, să spunem că vom opta să inițializăm variabila cu o nul valoare. Dacă ați evalua variabila folosind tip de ți-ar fi dat obiect rezultat.

// În primul rând, vom declara variabila var număr; / ** * În acest moment, dacă am fi evaluat variabila * folosind typeof, atunci ne-ar fi dat "nedefinit". * / // Atribuiți variabilei o valoare 'null' number = null; / ** * Și evaluați variabila. În acest moment, vom fi returnați valoarea "obiectului". * / tip (număr);

Derutant? Rețineți din mai devreme că în JavaScript, nul este un obiect unde undefined este tipul propriu - nedefinit

Cu acest lucru am spus că acum ne putem uita de ce comparațiile pot deveni dificile ori de câte ori efectuăm comparații asupra valorilor fără a cunoaște explicit tipul lor.

comparaţii

În această secțiune, vom examina rezultatele comparației valorilor care sunt de diferite tipuri, dar vom vedea cum sunt evaluate una față de cealaltă folosind atât comparații de egalitate, cât și comparații stricte cu egalitatea.

Rețineți că toate exemplele pe care le enumerăm mai jos ar trebui să poată fi executate în cadrul unei console de browser, cum ar fi Firebug sau Instrumentele de dezvoltare ale Chrome. 

Pentru începători, vom începe cu asta nedefinit și nul.

// Returneaza true undefined == null; null == undefined; // Returnează false undefined === null; null === undefined;

Observați că, în primul caz, operatorul de egalitate returnează o valoare a comparației după efectuarea coerciției de tip. Adică, interpretul își face cea mai bună estimare cu privire la ceea ce înțelegem atunci când efectuăm această comparație.

În cel de-al doilea caz, folosim operatorul strict de egalitate. În acest caz, nu apare nicio constrângere. În schimb, ia valorile exact așa cum sunt și le compară.

Apoi, să aruncăm o privire asupra declarării unei variabile, nu să o atribuim unei valori și apoi să efectuăm o comparație.

// Declare variabila, nu-i atribuiți o valoare var exemplu; // În comparație cu undefined, returnează adevărat în ambele cazuri example == undefined; exemplu === undefined // În comparație cu null, returnează exemplul adevărat sau fals == null; // adevărat exemplu === null; // false // Atribuiți o valoare variabilei example = null; // Acum face un exemplu strict de comparare === null; // Returnează adevărat

După cum puteți vedea, lucrurile încep să se complică mai mult când începem să declarăm și să comparăm variabilele cu sau fără valori.

Odată ce începem să introducem șiruri, numere și valori booleene, putem deveni și mai complicate. În primul rând, să începem cu șiruri de caractere și numere. Vom începe prin a declara o variabilă cu o valoare de șir de 42 și un număr cu 42 și apoi vom efectua comparațiile noastre. 

var sNumber, iNumber; sNumber = '42'; iNumber = 42; // Comparațiile de egalitate dau adevărat sNumber == iNumber; // Comparație strictă de randament sNumber false === iNumber;

Din nou, observați în primul caz, interpretul încearcă să forțeze valorile din variabile și apoi să le compare. În primul caz, funcționează - comparăm o valoare de șir de 42 la o valoare numerică de 42, dar când vom folosi comparația strictă a egalității și vom obține fals.

Cel de-al doilea caz este punct de vedere tehnic mai precis deoarece prima valoare este un șir și al doilea este un număr. Compararea a două valori de diferite tipuri ar trebui să dea întotdeauna fals.

Deși am aruncat o privire la acest lucru într-un articol anterior, cum rămâne cu cazul numerelor și booleanelor?

var iNumber, bBoolean; iNumber = 0; bBoolean = false; // Returnează iNumber adevărat == bBoolean; // Returnează falsul iNumber === bBoolean; // Returnează iNumber adevărat = 1; bBoolean = true; iNumber == bBoolean; // Returnează falsul iNumber === bBoolean;

În acest moment, ar trebui să începeți să observați un model: ori de câte ori comparați valori de diferite tipuri, JavaScript poate constrânge corect valorile, dar obține rezultatul cel mai precis atunci când utilizați operatorul de egalitate strictă.

În cele din urmă, să examinăm un exemplu care combină șiruri, numere și booleani.

var sExample, iExample, bExample; sExample = '1'; iExample = 1; bExample = adevărat; // Returnează true sExample == iExample; // Returnează false sExample === iExample; // Returnează true iExample == bExemplu; // Returnează falsul iExample === bExemplu; // Returnează true sExample == bExemplu; // Returnează false sExample === bExemplu;

Rețineți că acestea sunt comparații de bază; cu toate acestea, atunci când este făcut în contextul unui dacă / altceva sau dacă / altceva dacă / altceva vedeți cum poate întrerupe fluxul de control prin intermediul condiționării.

Altceva?

Rețineți că atunci când efectuați operații logice, cum ar fi && și || precum și operatorii de biți cum ar fi & și | că regulile de constrângere se aplică în continuare. În acest scop, doriți să vă asigurați că atunci când efectuați acele operații, utilizați valori de exact același tip pentru a obține rezultatele cele mai exacte.

În caz contrar, constrângerea poate avea ca rezultat un fals pozitiv sau un fals negativ.

Concluzie

Acest lucru completează uită-te, începător, privirea la tipurile de date și tipul de constrângere într-o limbă dinamică. În cele din urmă, regulile de bază sunt de a folosi mereu operatori stricți de egalitate și de a vă asigura că variabilele cu care lucrați sunt de același tip. Dacă nu sunteți sigur, puteți oricând să le convertiți în mod explicit utilizând strategiile pe care le-am prezentat mai devreme în serie.

De-a lungul acestei serii, am analizat modul în care tipurile variază și se comportă de la limbi puternic tipărite la limbi slabe scrise. Ne-am uitat la felul în care diferă difuzarea și constrângerea și am analizat unele dintre capcanele potențiale care ar putea conduce la a se baza prea mult pe interpret sau pe compilator atunci când efectuează comparații.

În cele din urmă, am analizat câteva strategii pentru scrierea unui cod mai defensiv, asigurându-ne că avem tipul de date de care avem nevoie și cum să folosim operatori de comparare stricți pentru a ne asigura că obținem rezultatele de care avem nevoie.

Așa cum am menționat anterior, am folosit JavaScript în scopurile exemplelor noastre în aceste articole grave, însă alte limbi slab tipărite sunt supuse acelorași capcane. Modul în care prioritățile coercițiilor lor variază, dar strategiile prezentate în această serie ar trebui să contribuie la scrierea unui cod mai rezistent atunci când lucrează în limbi slabe.  

Cod