Topp 10 saker som JavaScript blev fel

JavaScript, om det bara är standard, är ett av de mest populära programmeringsspråk som finns. Under årens lopp har det blivit märkt som en mardröm att arbeta med, och i viss utsträckning är detta sant! Men oftare men inte, vad folk menar att säga är att DOM API är en mardröm. Ändå finns det en handfull flat-out-fel på språket.

Jag skulle vilja göra en anteckning som jag älskar JavaScript. Denna artikel är endast avsedd för lite kul och för oss att vara medveten om några dess kortkomlingar.

1. Namnet. JavaScript är INTE Java

Vi börjar med en rolig jab vid namnvalet. Medan det ursprungligen kallades Mocha, och sedan LiveScript, ändrades det senare till JavaScript. Enligt historien var dess likheter med namnet Java resultatet av ett samarbete mellan Netscape och Sun, i utbyte mot Netscape som buntar Java runtime i sin populära webbläsare. Det har också noterats att namnet kom, nästan som ett skämt, på grund av rivaliteten mellan LiveScript och Java för script-scripting.

Ändå resulterade det i tusentals "JavaScript har inget att göra med Java" kommentarer i forum på webben!

2. Null är ett objekt?

Tänk på detta ...

 console.log (typof null); // objekt

Detta ger noll betydelse. Om null är frånvaron av ett värde, hur kan dess typ vara "objekt?" Det enkla svaret är att det är utplattat ett fel som går tillbaka till den första versionen av JavaScript - en som även var felaktigt överförd till Microsofts JScript.

3. NaNi == NaN

NaN, som vi förväntar oss hänvisar till ett värde som inte är ett lagligt nummer. Problemet är att NaN inte är lika med någonting ... inklusive sig själv.

 console.log (NaN === NaN); // false

Detta borde vara fel. Istället, om du vill bestämma om ett värde verkligen är NaN, kan du använda funktionen isNaN ().

Uppdatering: efter att ha läst igenom några av de strålande kommentarerna, särskilt de som hänför sig till NaN, liknar oändligheten, så är det så perfekt att NaN inte skulle motsvara sig. Men det kan fortfarande vara förvirrande. Se kommentarerna för en djupgående diskussion om detta!

4. Globala variabler

Beroendet av globala variabler anses allmänt vara den bortre delen av JavaScript långt ifrån. För enkla projekt, mycket som de snabba tipsen på den här webbplatsen, gör det inte någon skillnad. Men den verkliga bördan av globals kommer in i spel när du börjar referera till flera skript, utan någon kunskap om hur de skapas eller heter. Om de råkar dela samma namn som en av dina variabler, kommer ditt program att kasta något slags fel.

"Problemet med JavaScript är inte bara att det tillåter dem (globala variabler), det kräver dem." - Crockford

5. Användar-Agent Strängar Rapportera Mozilla. Någonsin undrar varför?

Okej - det här är inte Javascript-felet. Jag lurade lite. Det beror på webbläsarens leverantörer. Med detta sagt är användaragentsträngsdetektering mycket vanlig i JavaScript; så det är viktigt att veta vad du har att göra med. Det hör förmodligen inte i den här listan, men vem bryr sig! Det är bra att veta.

Det här är inte lika mycket ett misstag eftersom det var ett oundvikligt beslut. Öppna till exempel Safari, öppna webbinspektören och logga in användaragentsträngen i konsolen.

 console.log (navigator.userAgent); // Mozilla / 5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit / 531.21.8 (KHTML, som Gecko) Version / 4.0.4 Safari / 531.21.10

Observera att första sträng av tecken: Mozilla / 5,0. Varför skulle Safari identifiera det som en Mozilla-baserad webbläsare? Fast det senare identifierar sig själv, förklarar det fortfarande inte varför de skulle bry sig om att vilseleda programmerare. Faktum är att du upptäcker att de flesta webbläsare identifierar sig som Mozilla. Svaret går tillbaka ett decennium, och är, igen, mindre ett fel, och mer en oundviklig omständighet.

För de som är obekanta, är en användar-agent-sträng bara avsedd att identifiera webbläsaren och dess version. Som ett exempel hade den första någonsin webbläsaren, Mosaic, en användaragentsträng som såg ut så här:

 Mosaic / 0.9 // webbläsarens namn / versionsnummer

Detta gör perfekt mening. Och när Netscape kom på scenen, behöll de Mosaics användning, och lade också till en krypteringstypsektion.

 Mozilla / 2.02 [en] (Win95; I) // webbläsarens namn / version / kryptering

Än så länge är allt bra. Problemen kom till spel när - vänta på det - Internet Explorer 3 släpptes. Tänk på att när Netscape lanserade var Netscape den mest populära webbläsaren tillgänglig. Faktum är att många servrar och program redan genomförde detektering av användaragenter för att identifiera Netscape. Även om detta är ett mycket debatterat ämne idag, då var det inte mycket av ett problem. Om IE hade använt sin egen user-agent-sträng, skulle det ha sett något ut så här:

 MSIE / 3.0 (Win95; U)

Detta skulle ha lämnat dem i en stor nackdel, eftersom Netscape redan identifierades av många servrar. Som sådan beslutade utvecklarna att felaktigt identifiera webbläsaren som Mozilla och sedan lägga till en ytterligare uppsättning informationsmärkningar som Internet Explorer.

 Mozilla / 2.0 (kompatibel; MSIE 3.0; Windows 95)

Numera är användaragentdetektering en sista ansträngning, och den anses så exakt av den anledningen. Du kommer att upptäcka att de flesta webbläsare följde IE: s ledning när de identifierade sig som Mozilla. Tänk på det som en kedjereaktion.

Vidare läsning

Jag rekommenderar starkt att du läser Nicholas Zakas "Historia av användar-agentsträngen", om du skulle vilja dyka djupare.

6. Räckvidden inkonsekvenser

Tänk på följande kod:

 // Skapa en funktion som kallar en funktion med namnet lika med parameter fn. funktion foo (fn) om (typ av fn === "funktion") fn ();  // Skapa ett objekt med en egenskap och en metod. var bar = barbar: "Hej, Värld!", metod: funktion () alert (this.barbar); ; bar.method (); // Alerts Hej världen! foo (bar.method); // Om vi ​​kallar foo funktionen lägg till passera "bar.method" -metoden, det på något sätt varnar "odefinierad". foo (funktion () bar.method ();); // varningar Hello, World, after

Anledningen till att foo (bar.method) inte gör samma resultat beror på att metoden funktionen kommer att kallas som en metod för fönsterobjektet, snarare än bar. För att åtgärda detta måste vi ringa bar.method () inom den överlämnade anonyma funktionen.

Tack så mycket till Jeremy McPeak för att anmäla mig till det här felet.

7. Användningen av bitvisa operatörer

JavaScript delar många likheter med Java - en av dem är uppsättningen bitvisa operatörer.

  • & - och
  • | - eller
  • ^ - xor
  • ~ - inte
  • >> - signerad rätt skift
  • ??? - unsigned right shift
  • << - vänster Shift

Tänk på det första objektet, &; Det skulle vara mycket effektivare att använda &&-operatören, eftersom det är snabbare. Detta beror på att JavaScript inte är detsamma som Java, och har inte heltal. Som sådan krävs en relativt lång process för att konvertera operand, göra något med det och konvertera det sedan tillbaka.

Det är därför du kan komma undan med att använda & för "och" och | för "eller" - även om du ska använda && and ||.

8. För många falska / undervärden

Kanske är det inte ett särskilt fel i JavaScript, men det gör verkligen lärandeprocessen, speciellt för nybörjare, en hård. Värden som null, false och undefined betyder nästan samma sak, men det finns skillnader som kan vara förvirrande att förstå.

Falska värden

För att testa, öppna konsolen i Firefox och hitta den booleska av följande objekt.

 !!(0); // false !! (false); // false !! ("); // false !! (null); // false !! (undefined); // false !! (NaN); // false

Observera att alla andra värden tolkas som truthy.

Mer än ett fel är dessa många falska värden bara förvirrande!

9. Det kan inte göra aritmetiska

Okej okej, jag är 99% retande med rubriken ovan. Men JavaScript har några mindre problem när man arbetar med decimaler, till exempel saker som pengarransaktioner. Öppna till exempel din konsol och logga ".2 + .4". Vi förväntar oss att det ska visas ".6", korrekt? Jo det gör det, och det gör det inte!

 console.log (.2 + .4); // 0,6000000000000001

Hurså? På hög nivå beror det på att JavaScript använde IEEE-standarden för binär flytande punkträkning. Jag, förmodligen som du, förstår inte helt vad som specifierar, men vet bara att när man arbetar med decimalfraktioner kan resultaten variera något från vad man kan förvänta sig. Tänk på att heltalsräkning är perfekt, så det här är verkligen inte en stor fråga.

10. Kod Styling är inte ditt val!

När det gäller din kodning stil är det exakt det: din stil. Vissa föredrar att placera sina lockiga hängslen på samma sätt som kontrollen, andra föredrar att det går på egen hand.

 // fäste till höger retur foo: bar; // braces på egen linje retur foo: bar;

Beroende på den första web dev-boken vi läser, eller hur vår lärare lärde oss, är det helt acceptabelt att använda någon av metoderna ovan, eller till och med en kombination av de två. Problemet med JavaScript är att det inte är ditt val!

Jag lärde mig det här exemplet från en föreläsning som Doug Crockford gav för ungefär ett år sedan. Tänk på avkastningen från ovan. Tro det eller ej, de är inte lika. Tro mig inte? Prova detta. Lägg till följande på en viss HTML-sida.

 var foo = funktion () retur a: 'b';  (); alert (foo.a); // b

Koden ovan skapar helt enkelt en variabel som heter foo, vilket är lika med det returnerade objektet. När vi vaknar (foo.a) ser vi, som förväntat, en varningsruta med ett värde av "b". Nu ska du helt enkelt ta den öppnade locket, från returavkastningen och trycka den ner till sin egen linje, som så.

 returnera a: 'b';

Om du kör det i webbläsaren igen får du ett Firebug-fel och loggar på att "foo är odefinierad". Vad i helvete!? :)

Så varför gör JavaScript det här? Det beror på något som kallas "semicolon insertion". I huvudsak försöker JavaScript att korrigera vår dåliga kodning. Om du till exempel tror att du har avstått från en avslutande semikolon kommer den att fortsätta och lägga till den på dig. Även om detta ursprungligen var tänkt att vara en bekvämlighet, särskilt för nyare JavaScripters, är det faktiskt en mycket dålig sak när du inte har kontroll över din egen kod, vilket visas ovan.

I vårt exempel är det inte möjligt att bestämma varför foo.a returnerar "odefinierad". Nu när vi är medvetna om semikoloninläggning är anledningen till att den är odefinierad eftersom JavaScript lägger till en semikolon i slutet av returräkningen.

 lämna tillbaka; // JS lägger till felaktigt denna semikolon. a: "b"; // Det lägger till en semikolon här också, eftersom det inte inser att detta är ett objekt. ;

Så, om vi omedelbart återvänder, har ingen aning om vad egenskapen "a" är, vilket resulterar i "odefinierad".

Slutsats

Som jag nämnde i början av denna artikel älskar jag JavaScript och använder det dagligen. Men det betyder inte att det inte finns några riktigt hemska fel på språket. Jag skulle gärna höra dina tankar i kommentarerna! Tack för att du läser. Retweets och Diggs uppskattas alltid! Tack så mycket till Jeremy McPeak, Doug Crockford, Nicholas Zakas och John Resig: Jag hänvisade till dina handledning och böcker när du beredde denna artikel.

  • Följ oss på Twitter, eller prenumerera på Nettuts + RSS-flödet för de bästa webbutvecklingsstudierna på webben.