Domů O mně Služby Portfolio Učím Blog Kontakt
← Zpět na učím

2.8 For...in

Výuka

Co je for...in?

for...in iteruje přes klíče (vlastnosti) objektu. Na rozdíl od for...of, který iteruje přes hodnoty.

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

for (const key in obj) {
  console.log(key);  // "a", "b", "c" - KLÍČE
}

Kdy použít for...in?

Vhodné pro:

  • Iteraci přes vlastnosti objektu
  • Zjištění, jaké klíče objekt má
  • Dynamické zpracování objektů

NEPOUŽÍVEJ pro:

  • Pole (vrací indexy jako stringy, může zahrnout zděděné vlastnosti)
  • Když potřebuješ garantované pořadí

for...in vs for...of - Zásadní rozdíl!

const arr = ["a", "b", "c"];

// for...in - KLÍČE (indexy)
for (const key in arr) {
  console.log(key);  // "0", "1", "2" (stringy!)
}

// for...of - HODNOTY
for (const value of arr) {
  console.log(value);  // "a", "b", "c"
}

JavaScript

// Základní for...in na objektu
const user = {
  name: "Jan",
  age: 25,
  city: "Praha"
};

for (const key in user) {
  console.log(`${key}: ${user[key]}`);
}
// "name: Jan", "age: 25", "city: Praha"

// Problém: zděděné vlastnosti
const parent = { inherited: true };
const child = Object.create(parent);
child.own = "vlastní";

for (const key in child) {
  console.log(key);  // "own" A "inherited" - obě!
}

// Řešení: hasOwnProperty
for (const key in child) {
  if (child.hasOwnProperty(key)) {
    console.log(key);  // Jen "own"
  }
}

// Moderní alternativa: Object.hasOwn (ES2022)
for (const key in child) {
  if (Object.hasOwn(child, key)) {
    console.log(key);
  }
}

// POZOR na pole!
const fruits = ["jablko", "banán"];
fruits.customProp = "extra";  // Přidaná vlastnost

for (const key in fruits) {
  console.log(key);  // "0", "1", "customProp" - i extra vlastnost!
}

// Pro pole VŽDY použij for...of
for (const fruit of fruits) {
  console.log(fruit);  // "jablko", "banán" - jen prvky
}

// Dynamické zpracování objektu
const config = {
  debug: true,
  apiUrl: "https://api.example.com",
  timeout: 5000
};

for (const key in config) {
  const value = config[key];
  console.log(`Nastavení: ${key} = ${value}`);
}

// Kopírování objektu (shallow)
const original = { a: 1, b: 2 };
const copy = {};

for (const key in original) {
  copy[key] = original[key];
}

// Lepší způsob kopírování
const betterCopy = { ...original };
const betterCopy2 = Object.assign({}, original);

// Porovnání dvou objektů
function shallowEqual(obj1, obj2) {
  for (const key in obj1) {
    if (obj1[key] !== obj2[key]) {
      return false;
    }
  }
  for (const key in obj2) {
    if (!(key in obj1)) {
      return false;
    }
  }
  return true;
}

TypeScript

// Základní for...in s typy
const user = {
  name: "Jan",
  age: 25,
  city: "Praha"
};

for (const key in user) {
  // key je string, ne keyof typeof user!
  console.log(key);
}

// Problém: TypeScript neví přesný typ klíče
for (const key in user) {
  // ❌ Error: Element implicitly has 'any' type
  // console.log(user[key]);

  // ✅ Řešení: type assertion
  console.log(user[key as keyof typeof user]);
}

// Lepší: Object.entries nebo Object.keys
for (const [key, value] of Object.entries(user)) {
  // key: string, value: string | number
  console.log(`${key}: ${value}`);
}

// Type-safe iterace s keyof
type User = {
  name: string;
  age: number;
  email: string;
};

const userData: User = {
  name: "Jan",
  age: 25,
  email: "jan@email.cz"
};

// Pomocná funkce pro type-safe for...in
function forEachKey<T extends object>(
  obj: T,
  callback: (key: keyof T, value: T[keyof T]) => void
): void {
  for (const key in obj) {
    if (Object.hasOwn(obj, key)) {
      callback(key as keyof T, obj[key as keyof T]);
    }
  }
}

forEachKey(userData, (key, value) => {
  console.log(`${key}: ${value}`);
});

// Record typ
const translations: Record<string, string> = {
  hello: "ahoj",
  goodbye: "nashledanou"
};

for (const key in translations) {
  // key: string, translations[key]: string
  console.log(`${key} = ${translations[key]}`);
}

// Index signature
interface Config {
  [key: string]: string | number | boolean;
}

const config: Config = {
  debug: true,
  timeout: 5000
};

for (const key in config) {
  const value = config[key];  // string | number | boolean
  console.log(`${key}: ${value}`);
}

Rozdíl JS vs TS

JavaScript TypeScript
key je vždy string key je string, ale ne automaticky keyof
obj[key] bez problémů obj[key] může vyžadovat assertion
Žádná kontrola TS varuje před potenciálně chybným přístupem

Proč TypeScript "zlobí" s for...in?

const user = { name: "Jan", age: 25 };

for (const key in user) {
  // TypeScript neví, že key je "name" | "age"
  // Protože objekt může mít i další vlastnosti za runtime
  user[key];  // ❌ Error
}

// Řešení 1: Type assertion
user[key as keyof typeof user];

// Řešení 2: Object.keys s assertion
(Object.keys(user) as (keyof typeof user)[]).forEach(key => {
  console.log(user[key]);  // ✅ OK
});

// Řešení 3: Object.entries
Object.entries(user).forEach(([key, value]) => {
  console.log(key, value);  // ✅ OK
});

Tip

💡 Pro pole NIKDY nepoužívej for...in:

const arr = ["a", "b", "c"];

// ❌ ŠPATNĚ
for (const key in arr) {
  console.log(key);  // "0", "1", "2" (stringy!)
}

// ✅ SPRÁVNĚ
for (const value of arr) {
  console.log(value);  // "a", "b", "c"
}

// ✅ SPRÁVNĚ - když potřebuješ index
arr.forEach((value, index) => {
  console.log(index, value);
});

💡 Preferuj Object.keys/values/entries:

const obj = { a: 1, b: 2 };

// Modernější a čitelnější
Object.keys(obj);     // ["a", "b"]
Object.values(obj);   // [1, 2]
Object.entries(obj);  // [["a", 1], ["b", 2]]

// Použij s for...of
for (const [key, value] of Object.entries(obj)) {
  console.log(key, value);
}

💡 Filtruj zděděné vlastnosti:

for (const key in obj) {
  if (Object.hasOwn(obj, key)) {  // ES2022+
    // nebo: obj.hasOwnProperty(key)
    console.log(key);
  }
}

Kvíz

Které výroky jsou pravdivé?

- for...in iteruje přes KLÍČE, ne hodnoty (pro hodnoty je for...of)

- Indexy jsou vráceny jako stringy: "0", "1", "2"

- for...in zahrnuje i zděděné vlastnosti (proto používáme hasOwnProperty)

- Pro pole se doporučuje for...of nebo array metody, ne for...in

🎯 Závěrečný projekt

Po dokončení všech 8 dílů vytvoříte jednoduchou Todо aplikaci v čistém JavaScriptu. Naučíte se, jak aplikovat vše, co jste se naučili, na reálný projekt.

Zobrazit podrobnosti projektu →

Připraveni začít?

Zaregistrujte se a získejte přístup ke všem dílům tohoto seriálu

Kontaktujte mě

Informace o seriálu

Obtížnost

Délka

Cca 480 minut

Počet videí

8 videí + projekty

Certifikát

Po dokončení obdržíte certifikát


Lekce v této sekci


Struktura lekcí (souborový strom)

06. Typescript specifika
  • v přípravě
08. Moduly tridy
  • v přípravě
09. React zaklady
  • v přípravě
10. React hooks
  • v přípravě
12. Nextjs server
  • v přípravě
13. Databaze auth
  • v přípravě
14. Nextjs pokrocile
  • v přípravě