Často kladené otázky a odpovědi v JavaScriptovém rozhovoru

Znalost JavaScriptu výrazně navyšuje vaše vyhlídky na získání pozice softwarového vývojáře. Pojďme se tedy podívat na často pokládané dotazy při pracovních pohovorech zaměřených na JavaScript.

JavaScript je jedním z nejvíce rozšířených jazyků v oblasti vývoje webových aplikací. Dnes se používá pro vytváření téměř všech druhů aplikací.

Než se vrhneme na samotné otázky, probereme si výhody, které přináší učení JavaScriptu.

JavaScript je nenáročný, interpretovaný nebo just-in-time kompilovaný programovací jazyk. Je to jeden z klíčových pilířů globální sítě. Víte, jaké jsou další dva základní jazyky webu? Pokud ne, raději si je dohledejte.

JavaScript byl původně navržen pro webové prostředí. Nicméně, díky prostředí jako Node.js, Deno a dalším, ho lze nyní provozovat téměř na jakékoli platformě.

Podívejme se na některé z jeho výhod:

Výhody JavaScriptu

  • Je snadné s ním začít. Můžete se ho učit i bez předchozích zkušeností s programováním.
  • Má velkou a aktivní komunitu. Pokud se někde zaseknete, snadno najdete pomoc.
  • Existuje mnoho knihoven a frameworků postavených na JavaScriptu, což urychluje vývoj aplikací.
  • Umožňuje vytvářet frontendové, backendové, androidové, iOS a další typy aplikací. Je velmi univerzální, ale nejvíce se osvědčuje ve vývoji webových aplikací.

Jaké datové typy se používají v JavaScriptu?

Datové typy slouží k ukládání různých druhů dat. V jednotlivých programovacích jazycích se datové typy liší. V JavaScriptu máme 8 datových typů. Pojďme se na ně podívat jeden po druhém.

  • Číslo (Number)
  • Řetězec (String)
  • Logická hodnota (Boolean)
  • Nedefinováno (Undefined)
  • Null
  • BigInt
  • Symbol
  • Objekt (Object)

Všechny datové typy s výjimkou objektu se označují jako primitivní hodnoty. Tyto hodnoty jsou neměnné.

Jaké vestavěné metody JavaScript nabízí?

Vestavěné metody v JavaScriptu se liší v závislosti na datovém typu. K těmto metodám se dostaneme pomocí příslušného datového typu. Prozkoumejme některé vestavěné metody pro různé datové typy a datové struktury.

  • Číslo (Number)
  • Řetězec (String)
    • toLowerCase
    • startsWith
    • charAt
  • Pole (Array)

Pro každý datový typ existuje rozsáhlá škála vestavěných metod. Doporučujeme prostudovat si referenční materiály, abyste získali přehled o všech dostupných vestavěných metodách pro různé datové typy a struktury.

Jak se v JavaScriptu vytváří pole?

Pole představují základní datovou strukturu v JavaScriptu. Díky dynamické povaze JavaScriptu, mohou pole obsahovat data libovolného typu. Pojďme si ukázat, jak v JavaScriptu vytvářet pole.

Pole lze vytvořit pomocí hranatých závorek []. Tento způsob je rychlý a přímočarý.

// Prázdné pole
const arr = [];

// Pole s několika náhodnými hodnotami
const randomArr = [1, "One", true];

console.log(arr, randomArr);

Pole je také možné vytvořit pomocí konstruktoru Array. V běžných projektech se ale tento přístup používá zřídka.

// Prázdné pole
const arr = new Array();

// Pole s několika náhodnými hodnotami
const randomArr = new Array(1, "One", true);

console.log(arr, randomArr);

JavaScriptová pole jsou proměnlivá, což znamená, že je po vytvoření můžeme libovolně upravovat.

Jak se v JavaScriptu vytváří objekt?

Vedle polí je objekt další klíčovou datovou strukturou v JavaScriptu. Objekty slouží k ukládání párů klíč-hodnota. Klíč musí mít neměnnou hodnotu, zatímco hodnota může být libovolná. Podívejme se, jak v JavaScriptu objekty vytvářet.

Objekty lze vytvářet pomocí složených závorek {}. Tento způsob je rychlý a efektivní.

// Prázdný objekt
const object = {};

// Objekt s několika náhodnými hodnotami
const randomObject = { 1: 2, one: "Two", true: false };

console.log(object, randomObject);

Objekty lze vytvářet i pomocí konstruktoru Object. Nicméně, v běžných projektech se tento způsob používá ojediněle.

// Prázdný objekt
const object = new Object();

// Objekt s několika náhodnými hodnotami
const randomObject = new Object();
randomObject[1] = 2;
randomObject["one"] = "Two";
randomObject[true] = false;

console.log(object, randomObject);

JavaScriptové objekty jsou proměnlivé, tudíž je můžeme po vytvoření měnit, jak vidíte ve druhém příkladu.

Jak se v JavaScriptu ladí kód?

Ladění kódu nemusí být vždy snadné. Liší se v závislosti na programovacím jazyce, projektu atd. Prohlédněme si běžné metody používané pro ladění JavaScriptu.

1. Záznam do konzole (Logging)

K identifikaci chyb můžeme využít příkazy console.log na různých místech našeho kódu. Kód přestane provádět další řádky, jakmile se objeví chyba na předchozím řádku.

Logování je osvědčená a stále velmi účinná metoda pro ladění menších projektů. Jedná se o standardní techniku, kterou můžeme využít u libovolného programovacího jazyka.

2. Nástroje pro vývojáře

JavaScript se často používá pro vývoj webových aplikací. Proto téměř všechny prohlížeče obsahují nástroje pro vývojáře, které nám pomáhají ladit kód JavaScript.

Jednou z nejpopulárnějších metod ladění je nastavení zarážek v nástrojích pro vývojáře. Zarážky pozastaví provádění JavaScriptu a zobrazí nám všechny relevantní informace o aktuálním stavu provádění.

Můžeme nastavit několik zarážek v oblasti, kde předpokládáme chybu, abychom lépe pochopili její příčinu. Je to nejefektivnější způsob ladění webových aplikací napsaných v JavaScriptu.

3. Vývojová prostředí (IDE)

K ladění JavaScriptu můžeme také využít vývojová prostředí IDE. Například VS Code nabízí podporu ladění pomocí zarážek. Funkce ladění se mohou lišit v závislosti na IDE, které používáte, ale většina IDE tuto funkci nabízí.

Jak vložit JavaScriptový kód do HTML souboru?

JavaScriptový kód lze do HTML dokumentu vložit pomocí značky <script>. Zde je příklad:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>etechblog.cz</title>
  </head>
  <body>
    <h1>etechblog.cz</h1>

    <script>
      // Zde vložte JavaScriptový kód
      console.log("Tohle je JavaScriptový kód");
    </script>
  </body>
</html>

Co jsou to cookies?

Cookies jsou páry klíč-hodnota používané k uchovávání malých informací. Tyto informace mohou mít libovolný charakter. U cookies můžeme nastavit dobu vypršení platnosti, po které budou automaticky smazány. Běžně se používají k ukládání informací o uživatelích.

Cookies se nesmažou, ani když stránku obnovíme. Smažou se až v případě, že to uděláme ručně nebo vyprší jejich platnost. Cookies jakékoli webové aplikace či stránky lze zkontrolovat v nástrojích pro vývojáře ve vašem prohlížeči.

Jak se cookies čtou?

Cookies můžeme číst v JavaScriptu pomocí document.cookie. Tato metoda vrátí všechny vytvořené cookies.

console.log("Všechny cookies", document.cookie);

Pokud žádné cookies neexistují, vrátí se prázdný řetězec.

Jak se vytvářejí a mažou cookies?

Cookies můžeme vytvořit nastavením páru klíč–hodnota na document.cookie. Podívejme se na příklad.

document.cookie = "one=One;";

Ve výše uvedené syntaxi představuje klíč cookie „one“ a jeho hodnotu „One“. Ke cookie můžeme přidat další atributy jako „domain“, „path“, „expires“ atd. Každý z atributů musí být oddělen středníkem (;). Všechny atributy jsou volitelné.

Zde je příklad s atributy:

document.cookie = "one=One;expires=Jan 31 2023;path=/;";

V uvedeném příkladu jsme k cookie přidali datum vypršení platnosti a cestu. Pokud není nastaveno datum expirace, cookie bude smazána po skončení relace. Výchozí cesta bude cesta k souboru. Datum vypršení platnosti by mělo být ve formátu GMT.

Podívejme se, jak se vytváří více cookies:

document.cookie = "one=One;expires=Jan 31 2023;path=/;";
document.cookie = "two=Two;expires=Jan 31 2023;path=/;";
document.cookie = "three=Three;expires=Jan 31 2023;path=/;";

Cookies se nepřepíší, pokud se klíč nebo cesta při vytváření liší. Pokud jsou klíč a cesta stejné, předchozí cookie se přepíše. Následující příklad ukazuje, jak se přepíše dříve nastavená cookie.

document.cookie = "one=One;expires=Jan 31 2023;path=/;";
document.cookie = "one=Two;path=/;";

V tomto kódu jsme odstranili datum vypršení platnosti a změnili hodnotu.

Při testování, zda kód správně funguje, používejte datum vypršení platnosti v budoucnosti. Pokud použijete datum 31. ledna 2023 i po 31. lednu 2023, cookies se nevytvoří.

Ukázali jsme si, jak cookies vytvářet a aktualizovat. Nyní se podíváme, jak se cookies mažou.

Mazání cookies je jednoduché. Stačí změnit datum vypršení platnosti na libovolné datum v minulosti. Zde je příklad:

// Vytvoření cookies
document.cookie = "one=One;expires=Jan 31 2023;path=/;";
document.cookie = "two=Two;expires=Jan 31 2023;path=/;";
document.cookie = "three=Three;expires=Jan 31 2023;path=/;";

// Smazání poslední cookie
document.cookie = "three=Three;expires=Jan 1 2023;path=/;";

Poslední cookie v cookie už nenajdete, protože byla smazána posledním řádkem kódu. To je vše k tomuto mininávodu o cookies.

Jaké jsou různé JavaScriptové frameworky?

Existuje mnoho JavaScriptových frameworků. Například React, Vue, Angular se používají pro vývoj uživatelského rozhraní. Express, Koa, Nest a další pro vývoj na straně serveru. NextJS, Gatsby atd. pro generování statických stránek. React Native, Ionic a další pro vývoj mobilních aplikací. To je jen několik frameworků. Je jich mnohem více a jejich zkoumání by zabralo spoustu času. Proto je prozkoumejte, až je budete potřebovat.

Uzávěry (Closures) v JavaScriptu

Uzávěr je funkce spojená se svým lexikálním rozsahem a nadřazeným lexikálním prostředím. Díky uzávěrům máme přístup k datům z vnějšího rozsahu. Uzávěry se vytvářejí při definování funkcí.

function outer() {
  const a = 1;
  function inner() {
    // Zde máme přístup ke všem datům z vnějšího rozsahu funkce
    // Data budou dostupná, i když tuto funkci spustíme mimo vnější funkci
    // protože uzávěr vnitřní funkce vznikl při jejím vytvoření
    console.log("Přístup k a uvnitř inner", a);
  }
  return inner;
}

const innerFn = outer();
innerFn();

Uzávěry se v JavaScriptových aplikacích hojně využívají. Je možné, že jste je používali i bez toho, aniž byste si uvědomovali, že se o uzávěry jedná. O uzávěrech se můžete dozvědět mnohem více. Určitě si tento koncept důkladně prostudujte.

Zvedání (Hoisting) v JavaScriptu

Zvedání je proces v JavaScriptu, kdy se deklarace proměnných, funkcí a tříd přesunou na začátek rozsahu ještě před tím, než se spustí kód.

// Přístup k `name` před jeho deklarací
console.log(name);

// Deklarace a inicializace `name`
var name = "etechblog.cz";

Pokud spustíte výše uvedený kód, neobjeví se žádná chyba. Ve většině jiných jazyků byste však chybu dostali. Výstup bude „undefined“, protože zvedání přesune pouze deklaraci nahoru, inicializace se provede až na řádku č. 3.

Změňte „var“ na „let“ nebo „const“, jak vidíte níže, a spusťte kód znovu.

// Přístup k `name` před jeho deklarací
console.log(name);

// Deklarace a inicializace `name`
const name = "etechblog.cz";

Nyní se objeví „ReferenceError“ oznamující, že před inicializací nemůžeme k proměnné přistoupit.

ReferenceError: Cannot access 'name' before initialization

To je důvod, proč byly v ES6 zavedeny „let“ a „const“, ke kterým nemůžeme přistoupit před jejich inicializací. Proměnné deklarované pomocí „let“ nebo „const“ se nacházejí v takzvané časové mrtvé zóně (TDZ – Temporal Dead Zone), dokud není daný řádek inicializován. K proměnným z TDZ tedy nemáme přístup.

Currying v JavaScriptu

Currying je technika pro transformaci funkcí s více parametry na funkce s méně parametry, které se volají postupně. Díky ní můžeme transformovat funkci „add(a, b, c, d)“ na „add(a)(b)(c)(d)“. Podívejme se na příklad:

function getCurryCallback(callback) {
  return function (a) {
    return function (b) {
      return function (c) {
        return function (d) {
          return callback(a, b, c, d);
        };
      };
    };
  };
}

function add(a, b, c, d) {
  return a + b + c + d;
}

const curriedAdd = getCurryCallback(add);

// Volání curriedAdd
console.log(curriedAdd(1)(2)(3)(4));

Funkci „getCurryCallback“ můžeme zobecnit, aby se dala použít pro transformaci různých funkcí na curried funkce. Další informace o JavaScriptu najdete v sekci „O JavaScriptu“.

Rozdíl mezi objektem „document“ a „window“

Objekt „window“ je nejvyšší objekt v prohlížeči. Obsahuje všechny informace o okně prohlížeče, jako je historie, poloha, navigátor atd. V JavaScriptu je globálně dostupný, můžeme ho tedy používat přímo v našem kódu bez nutnosti jakýchkoli importů. K vlastnostem a metodám objektu „window“ můžeme přistupovat i bez explicitního uvádění „window“.

Objekt „document“ je součástí objektu „window“. Veškerý HTML kód načtený na webové stránce se transformuje na objekt „document“. Objekt „document“ odkazuje na specifický prvek HTMLDocument, který má jiné vlastnosti a metody než ostatní HTML prvky.

Objekt „window“ reprezentuje okno prohlížeče a objekt „document“ představuje HTML dokument, který se v okně prohlížeče načetl.

Rozdíl mezi klientskou a serverovou stranou

Klientská strana se vztahuje na koncového uživatele, který aplikaci používá. Serverová strana se vztahuje k webovému serveru, kde je aplikace nasazena.

Z pohledu frontendu můžeme říci, že prohlížeč na počítačích uživatelů je klientská strana a cloudové služby představují stranu serveru.

Rozdíl mezi innerHTML a innerText

Jak „innerHTML“, tak „innerText“ jsou vlastnosti HTML elementů. Pomocí těchto vlastností můžeme měnit obsah HTML elementu.

Vlastnosti „innerHTML“ můžeme přiřadit HTML řetězec, který se pak zobrazí jako běžný HTML kód. Podívejte se na následující příklad:

const titleEl = document.getElementById("title");

titleEl.innerHTML = '<span style="color:orange;">etechblog.cz</span>';

Přidejte do HTML souboru element s id „title“ a výše uvedený skript do JavaScriptového souboru. Spusťte kód a podívejte se na výstup. Zobrazí se vám text „etechblog.cz“ v oranžové barvě. Pokud element zkontrolujete, bude uvnitř značky span. To znamená, že „innerHTML“ vezme HTML řetězec a vykreslí ho jako běžný HTML kód.

Naproti tomu, „innerText“ vezme běžný řetězec a vykreslí ho tak, jak je, bez jakéhokoli HTML formátování. Změňte „innerHTML“ na „innerText“ ve výše uvedeném kódu a zkontrolujte výstup:

const titleEl = document.getElementById("title");

titleEl.innerText="<span style="color:orange;">etechblog.cz</span>";

Nyní se na webové stránce zobrazí přesně ten řetězec, který jsme zadali.

Rozdíl mezi „let“ a „var“

Klíčová slova „let“ a „var“ se v JavaScriptu používají pro deklaraci proměnných. Klíčové slovo „let“ bylo zavedeno v ES6.

Proměnná deklarovaná pomocí „let“ má rozsah ohraničený blokem, zatímco „var“ má rozsah ohraničený funkcí.

{
  let a = 2;
  console.log("Uvnitř bloku", a);
}
console.log("Mimo blok", a);

Spusťte výše uvedený kód. Na posledním řádku se objeví chyba, protože k proměnné „a“ nemůžeme přistupovat mimo blok, protože má rozsah ohraničený blokem. Nyní nahraďte „let“ za „var“ a spusťte ho znovu:

{
  var a = 2;
  console.log("Uvnitř bloku", a);
}
console.log("Mimo blok", a);

Žádná chyba se nezobrazí, protože k proměnné „a“ můžeme přistupovat i mimo blok. Nyní nahradíme blok funkcí:

function sample() {
  var a = 2;
  console.log("Uvnitř funkce", a);
}
sample();
console.log("Mimo funkci", a);

Pokud spustíte výše uvedený kód, dostanete chybu „ReferenceError“, protože k proměnné „a“ nemůžeme přistupovat mimo funkci, protože má rozsah ohraničený funkcí.

Proměnné deklarované pomocí „var“ můžeme deklarovat opakovaně, ale proměnné deklarované pomocí „let“ opakovaně deklarovat nemůžeme. Podívejte se na příklad:

var a = "etechblog.cz";
var a = "Chandan";
console.log(a);
let a = "etechblog.cz";
let a = "Chandan";
console.log(a);

První část kódu nezpůsobí žádnou chybu a hodnota proměnné „a“ bude změněna na poslední přiřazenou hodnotu. Druhá část kódu způsobí chybu, protože proměnné pomocí „let“ nemůžeme deklarovat opakovaně.

Rozdíl mezi Session Storage a Local Storage

Session Storage a Local Storage se používají k uchovávání informací na počítačích uživatelů. Tyto informace jsou dostupné i bez připojení k internetu. Jak do Session Storage, tak do Local Storage můžeme ukládat páry klíč-hodnota. Pokud použijeme jiný datový typ nebo datovou strukturu, klíč i hodnota se převedou na řetězce.

Session Storage se smaže po skončení relace (zavření prohlížeče). Local Storage se nesmaže, dokud ho nesmažeme ručně.

K Session Storage a Local Storage můžeme přistupovat, aktualizovat je a odstraňovat je pomocí objektů „sessionStorage“ a „localStorage“.

Co je to NaN v JavaScriptu?

NaN je zkratka pro „Not-a-Number“. Znamená to, že v JavaScriptu něco není platné číslo. NaN jako výstup dostaneme například v případech jako 0/0, undefined * 2, 1 + undefined, null * undefined atd.

Co je lexikální rozsah (Lexical Scoping)?

Lexikální rozsah se vztahuje k přístupu k proměnným z jejich rodičovských rozsahů. Řekněme, že máme funkci se dvěma vnořenými funkcemi. Nejvíce vnořená funkce má přístup k proměnným z obou svých rodičovských rozsahů. Podobně, funkce druhé úrovně má přístup k nejvzdálenějšímu rozsahu funkce. Podívejme se na příklad:

function outermost() {
  let a = 1;
  console.log(a);
  function middle() {
    let b = 2;
    // `a` je zde přístupné
    console.log(a, b);
    function innermost() {
      let c = 3;
      // `a` i `b` jsou zde přístupné
      console.log(a, b, c);
    }
    innermost();
  }
  middle();
}
outermost();

JavaScript používá řetězec rozsahů k nalezení proměnné, když k ní někde v kódu přistupujeme. Nejdříve se proměnná hledá v aktuálním rozsahu, poté v rodičovském rozsahu a tak dále až ke globálnímu rozsahu.

Co je předávání hodnotou (Pass by Value) a předávání odkazem (Pass by Reference)?

Předávání hodnotou a předávání odkazem jsou dva způsoby, jak v JavaScriptu předávat argumenty do funkce.

Při předávání hodnotou se vytváří kopie původních dat, která se pak předá funkci. To znamená, že když ve funkci provedeme nějakou změnu, původní data se tím neovlivní. Následující příklad to demonstruje:

function sample(a) {
  // Změna hodnoty `a`
  a = 5;
  console.log("Uvnitř funkce", a);
}
let a = 3;
sample(a);
console.log("Mimo funkci", a);

Vidíte, že původní hodnota „a“ se nezmění, i když jsme ji uvnitř funkce změnili.

Při předávání odkazem se do funkce předá odkaz na data. To znamená, že když uvnitř funkce provedeme nějakou změnu, změní se i původní data.

function sample(arr) {
  // Přidání nové hodnoty do pole
  arr.push(3);
  console.log("Uvnitř funkce", arr);
}
let arr = [1, 2];
sample(arr);
console.log("Mimo funkci", arr);

Vidíte, že původní hodnota „arr“ se změní, když ji uvnitř funkce změníme.

Poznámka: Všechny primitivní datové typy se předávají hodnotou a neprimitivní datové typy se předávají odkazem.

Co je memoizace?

Memoizace je technika, která ukládá vypočtené hodnoty do mezipaměti a využívá je, když je potřebujeme znovu, aniž bychom je museli znovu počítat. Pokud je výpočet velmi náročný, může memoizace zrychlit provádění kódu. Je tu ovšem kompromis, jelikož musíme ukládat do paměti, nicméně to ve srovnání s ušetřeným časem nepředstavuje velký problém.

const memo = {};
function add(a, b) {
  const key = `${a}-${b}`;

  // Kontrola, zda jsme již hodnotu spočítali
  if (memo[key]) {
    console.log("Znovu se nepočítá");
    return memo[key];
  }

  // Přidání nově spočtené hodnoty do mezipaměti
  // mezipaměť je zde jednoduchý globální objekt
  memo[key] = a + b;
  return memo[key];
}

console.log(add(1, 2));
console.log(add(2, 3));
console.log(add(1, 2));

To je jednoduchý příklad demonstrující memoizaci. Sčítání dvou čísel zde nepředstavuje žádný náročný výpočet, je to jen pro ilustraci.

Co je zbytek parametru (Rest Parameter)?

Zbytek parametru slouží ke shromáždění všech zbývajících parametrů ve funkci. Řekněme, že máme funkci, která bude akceptovat minimálně 2 argumenty a může akceptovat libovolný maximální počet parametrů. Jelikož nemáme stanovený maximální počet argumentů, můžeme shromáždit první 2 parametry pomocí běžných proměnných a všechny zbývající pomocí zbytkového parametru, a to pomocí rest operátoru.

function sample(a, b, ...rest) {
  console.log("Zbytek parametru", rest);
}

sample(1, 2, 3, 4, 5);

Zbytek parametru bude v uvedeném příkladu polem posledních tří argumentů. Díky tomu můžeme funkci přiřadit libovolný počet parametrů.

Funkce může mít pouze jeden zbytkový parametr a tento parametr by měl být v pořadí parametrů poslední.

Co je destrukce objektu (Object Destructuring)?

Destrukce objektu se používá pro přístup k proměnným z objektu a jejich přiřazení k proměnným se stejnými názvy jako klíče objektu. Zde je příklad:

const object = { a: 1, b: 2, c: 3 };

// Destrukce objektu
const { a, b, c } = object;

// Nyní se a, b a c budou používat jako běžné proměnné
console.log(a, b, c);

Proměnným destrukturovaných proměnných můžeme na stejném řádku změnit názvy, jak vidíte níže:

const object = { a: 1, b: 2, c: 3 };

// Změna názvů `a` a `b`
const { a: changedA, b: changedB, c } = object;

// Nyní se changedA