10 chyb, které začátečníci JavaScriptu často dělají

JavaScript je jednoduchý jazyk, se kterým se začíná, ale jeho zvládnutí vyžaduje hodně úsilí. Začátečníci často dělají pár známých chyb, které se vracejí a skousnou je, když to nejméně čekají. Chcete-li zjistit, které tyto chyby jsou, pokračujte ve čtení!

1. Chybí složené závorky

Jednou praxí, kterou se začátečníci v JavaScriptu často dopouštějí, je vynechávání složených závorek za příkazy jako if , else , while a for . I když je to povoleno, měli byste být obzvláště opatrní, protože tento postup může často skrývat problémy a být zdrojem chyb. Viz níže uvedený příklad:

// Say hello to Gandalf
hello('Gandalf');

function hello(name){

    // This code doesn't do what the indentation implies!

    if(name === undefined)
        console.log('Please enter a username!');
        fail();

    // The following line is never reached:

    success(name);
}

function success(name){
    console.log('Hello, ' + name + '!');
}

function fail(){
    throw new Error("Name is missing. Can't say hello!");
}

Ačkoli fail() volání je odsazené a vypadá, jako by patřilo do if prohlášení, není. Vždy se to říká. Je tedy dobrým zvykem vždy obklopit bloky kódu složenými závorkami, i když se jedná pouze o jeden příkaz.

2. Chybí středníky

Při analýze JavaScriptu dochází k procesu známému jako automatické vkládání středníků. Jak název napovídá, parser za vás rád vloží chybějící středníky. Účelem této funkce je učinit JavaScript přístupnějším a snadnějším pro začátečníky. Vždy byste však měli zahrnout středníky, protože jejich vynechání je nebezpečné. Zde je příklad:

// This code results in a type error. Adding semicolons will fix it.

console.log('Welcome the fellowship!')

['Frodo', 'Gandalf', 'Legolas', 'Gimli'].forEach(function(name){
    hello(name)
})

function hello(name){
    console.log('Hello, ' + name + '!')
}

Protože na řádku 3 chybí středník, analyzátor předpokládá, že otevírací závorka na řádku 5 je pokus o přístup k vlastnosti pomocí syntaxe přístupového objektu pole (viz chyba #8), a nikoli samostatné pole, což není to, co bylo zamýšlený a vede k chybě typu. Oprava je jednoduchá – vždy pište středníky.

Někteří zkušení vývojáři JavaScriptu raději vynechávají středníky, ale jsou si dobře vědomi chyb, které to může způsobit, a vědí, jak jim předejít.

3. Nepochopení typu nátlak

JavaScript se zadává dynamicky. To znamená, že při deklaraci nové proměnné nemusíte zadávat typ a její hodnotu můžete libovolně přiřadit nebo převést. To usnadňuje psaní JavaScriptu než něco jako C# nebo Java, ale otevíráte dveře pro potenciální chyby, které jsou v jiných jazycích zachyceny během kompilace. Zde je příklad:

// Listen for the input event on the textbox

var textBox = document.querySelector('input');

textBox.addEventListener('input', function(){

    // textBox.value holds a string. Adding 10 appends 
    // the string '10', it doesn't perform an addition..

    console.log(textBox.value + ' + 10 = ' + (textBox.value + 10));

});
<input type="number" placeholder="Enter a number here" />

Problém lze snadno vyřešit pomocí parseInt(textBox.value, 10) proměnit řetězec na číslo, než k němu přidáte 10. V závislosti na tom, jak proměnnou používáte, se může běhové prostředí rozhodnout, že by měla být převedena do jednoho nebo druhého typu. Toto je známé jako typ nátlaku. Aby se zabránilo implicitnímu převodu typů při porovnávání proměnných v if můžete použít přísné kontroly rovnosti (===).

4. Zapomínání var

Další praktikou, kterou se začátečníci dopouštějí, je zapomenutí použít var klíčové slovo při deklaraci proměnných. JavaScript je velmi tolerantní a poprvé zjistí, že jste použili proměnnou bez var prohlášení, tiše to za vás globálně prohlásí. To může být zdrojem jemných chyb. Zde je příklad, který také ukazuje jinou chybu – chybějící čárku při deklarování více proměnných najednou:

var a = 1, b = 2, c = 3;

function alphabet(str){
    var a = 'A', b = 'B'    // Oops, missing ',' here!
        c = 'C', d = 'D';

    return str + ' ' + a + b + c + '…';
}

console.log( alphabet("Let's say the alphabet!") );

// Oh no! Something went wrong! c has a new value!
console.log(a, b, c);

Když analyzátor dosáhne řádku 4, automaticky vloží středník a poté interpretuje c a d deklarace na řádku 5 jako globální. To způsobí změnu hodnoty vnější proměnné c. Přečtěte si o dalších funkcích JavaScript zde.

5. Aritmetické operace s plováky

Tato chyba platí pro téměř každý programovací jazyk, včetně JavaScriptu. Kvůli způsobu, jakým jsou čísla s plovoucí desetinnou čárkou reprezentována v paměti, nejsou aritmetické operace tak přesné, jak byste si mysleli. Zde je příklad:

var a = 0.1, b = 0.2;

// Surprise! this is false:
console.log(a + b == 0.3);

// Because 0.1 + 0.2 does not produce the number that you expect:
console.log('0.1 + 0.2 = ', a + b);

Chcete-li tento problém vyřešit, neměli byste používat desetinná místa, pokud potřebujete absolutní správnost – použijte celá čísla, nebo pokud potřebujete pracovat s penězi, použijte knihovnu jako bignumber.js.

6. Použití konstruktorů nad literály

Když programátoři Java a C# začnou psát JavaScript, často dávají přednost vytváření objektů pomocí konstruktorů:new Array() , new Object() , new String() . Přestože jsou dokonale podporovány, doporučuje se používat doslovný zápis:[] , {} , "" , protože funkce konstruktoru mají jemné zvláštnosti:

/* Using array constructors is valid, but not recommended. Here is why. */

// Create an array with four elements:

var elem4 = new Array(1,2,3,4);

console.log('Four element array: ' + elem4.length);

// Create an array with one element. It doesn't do what you think it does:

var elem1 = new Array(23);

console.log('One element array? ' + elem1.length);

/* String objects also have their warts */

var str1 = new String('JavaScript'),
    str2 = "JavaScript";

// Strict equality breaks:

console.log("Is str1 the same as str2?", str1 === str2);

Řešení je jednoduché:snažte se vždy používat doslovný zápis. Kromě toho pole JS nepotřebují znát svou délku předem.

7. Nerozumím tomu, jak fungují rozsahy

Pro začátečníky obtížně pochopitelný koncept jsou pravidla a uzávěry JavaScriptu. A právem:

// Print the numbers from 1 to 10, 100ms apart. Or not.

for(var i = 0; i < 10; i++){
    setTimeout(function(){
        console.log(i+1);
    }, 100*i);
}

/* To fix the bug, wrap the code in a self-executing function expression:

for(var i = 0; i < 10; i++){

    (function(i){
        setTimeout(function(){
            console.log(i+1);
        }, 100*i);
    })(i);

}               

*/

Funkce si zachovávají viditelnost proměnných ve svých nadřazených oborech. Ale protože zdržujeme provedení pomocí setTimeout , když nastane čas, kdy se funkce skutečně spustí, smyčka již skončila a i proměnná se zvýší na 11.

Samospouštěcí funkce v komentáři funguje, protože kopíruje i proměnné podle hodnoty a uchovává soukromou kopii pro každou funkci časového limitu. Přečtěte si více o rozsahu zde a zde.

8. Pomocí eval

Eval je zlý. Je to považováno za špatnou praxi a ve většině případů, kdy ji používáte, existuje lepší a rychlejší přístup.

/* Using eval to access properties dynamically */

var obj = {
    name: 'Foo Barski',
    age: 30,
    profession: 'Programmer'
};

// Which property to access?
var access = 'profession';

// This is a bad practice. Please don't do it:
console.log( eval('obj.name + " is a " + obj.' + access) );

// Instead, use array notation to access properties dynamically:
console.log( obj.name + " is a " + obj[access]);

/* Using eval in setTimout */

// Also bad practice. It is slow and difficult to read and debug:
setTimeout(' if(obj.age == 30) console.log("This is eval-ed code, " + obj[access] + "!");', 100);

// This is better:
setTimeout(function(){

    if(obj.age == 30){
        console.log('This code is not eval-ed, ' + obj[access] + '!');
    }

}, 100);

Kód uvnitř eval je řetězec. Debug zprávy vznikající z eval bloků jsou nesrozumitelné a musíte žonglovat s unikajícími jednoduchými a dvojitými uvozovkami. Nemluvě o tom, že je pomalejší než běžný JavaScript. Nepoužívejte eval, pokud nevíte, co děláte.

9. Nerozumím asynchronnímu kódu

Něco, co je jedinečné pro JavaScript, je to, že téměř vše je asynchronní a musíte předat funkce zpětného volání, abyste byli informováni o událostech. Začátečníkům to nepřijde intuitivně a rychle zjistí, že se škrábou na hlavě na těžko pochopitelném brouku. Zde je příklad, ve kterém používám službu FreeGeoIP k načtení vaší polohy podle IP:

var userData = {};

// Fetch the location data for the current user.
load();

// Output the location of the user. Oops, it doesn't work! Why?
console.log('Hello! Your IP address is ' + userData.ip + ' and your country is ' + userData.country_name);

// The load function will detect the current visitor's ip and location with ajax, using the
// freegeoip service. It will place the returned data in the userData variable when it's ready.

function load(){

    $.getJSON('https://freegeoip.net/json/?callback=?', function(response){
        userData = response;

        // Uncomment this line to see what is returned:
        // console.log(response);
    });
}

I když console.log následuje za load() volání funkce, je ve skutečnosti provedeno před načtením dat.

10. Zneužití posluchačů událostí

Řekněme, že chcete poslouchat kliknutí na tlačítko, ale pouze při zaškrtnutém políčku. Zde je návod, jak to může udělat začátečník (pomocí jQuery):

var checkbox = $('input[type=checkbox]'),
    button = $('button');

// We want to listen for clicks only when the checkbox is marked.

checkbox.on('change', function(){

    // Is the checkbox checked?

    if(this.checked){

        // Listen for clicks on the button. 

        button.on('click', function(){

            // This alert is called more than once. Why?

            alert('Hello!');
        });
    }
});
<input type="checkbox" />

<button>Click me!</button>

<p>Click the checkbox a few times.</p>

To je evidentně špatně. V ideálním případě byste měli událost poslouchat pouze jednou, jako jsme to udělali u události změny zaškrtávacího políčka. Opakované volání button.on('click' ..) výsledkem je více posluchačů událostí, které nejsou nikdy odstraněny. Nechám to jako cvičení pro čtenáře, aby tento příklad fungoval :)

Závěr

Nejlepší způsob, jak zabránit podobným chybám, je použít JSHint. Některá IDE nabízejí vestavěnou integraci s nástrojem, takže váš kód je při psaní kontrolován. Doufám, že vás tento seznam zaujal. Pokud máte nějaké návrhy, uveďte je do sekce komentářů!