15 Najtrudniejszych Pytań z JavaScript 2026: Closure, This i Event Loop - Flipcards

15 Najtrudniejszych Pytań z JavaScript 2026: Closure, This i Event Loop

Sławomir Plamowski 18 min czytania
frontend javascript programowanie pytania-rekrutacyjne rozmowa-rekrutacyjna

15 Najtrudniejszych Pytań z JavaScript 2026: Closure, This i Event Loop

Dlaczego ten kod wypisuje trzy razy liczbę 3 zamiast 0, 1, 2? To klasyczne pytanie z pętlą for i setTimeout potrafi zaskakiwać nawet programistów z wieloletnim doświadczeniem. Odpowiedź wymaga połączenia wiedzy o closure, scope i asynchroniczności - a właśnie takie pytania najczęściej padają na rozmowach rekrutacyjnych.

Najtrudniejsze pytania z JavaScript nie dotyczą egzotycznych API czy obscurycznych edge case'ów. Dotyczą fundamentów języka - rzeczy, które używamy codziennie, ale rzadko się nad nimi zastanawiamy. Poniżej znajdziesz 15 pytań, które konsekwentnie sprawiają trudności nawet doświadczonym programistom. To nie są pytania-zagadki ani gotcha questions wymyślone żeby kogoś przyłapać - to pytania, które naprawdę weryfikują zrozumienie JavaScript na głębokim poziomie.

Spis Treści

  1. Podstawowe Koncepty Pytania
  2. Asynchroniczność i Event Loop Pytania
  3. Obiekty i Prototypy Pytania
  4. Składnia i Operatory Pytania
  5. Funkcje i Zasięg Pytania

Podstawowe Koncepty Pytania

Rozpoczynamy od fundamentalnych konceptów, które stanowią podstawę JavaScript. Te pytania sprawdzają czy rozumiesz jak język działa pod spodem.

Czym jest closure w JavaScript i jak działa?

Closure to funkcja wewnętrzna, która 'pamięta' zmienne z zakresu, w którym została utworzona, nawet gdy ten zakres już nie istnieje. Mechanizm ten pozwala funkcji wewnętrznej na dostęp do zmiennych funkcji zewnętrznej nawet po jej zakończeniu, dzięki zachowaniu referencji do środowiska leksykalnego.

W praktyce closure używamy do tworzenia prywatnych zmiennych, funkcji fabrykujących i implementacji wzorca modułu. Jest to jeden z najważniejszych mechanizmów JavaScript, który stoi za wieloma wzorcami programistycznymi.

function createCounter() {
    let count = 0;  // ta zmienna jest 'zamknięta' w closure

    return function() {
        count++;
        return count;
    };
}

const counter = createCounter();
console.log(counter());  // 1
console.log(counter());  // 2
console.log(counter());  // 3

// Każde wywołanie createCounter tworzy nowy, niezależny closure
const anotherCounter = createCounter();
console.log(anotherCounter());  // 1 (nie 4!)

Klasyczny problem z pętlą i setTimeout:

for (var i = 0; i < 3; i++) {
    setTimeout(function() {
        console.log(i);  // Wypisuje: 3, 3, 3
    }, 1000);
}

Dlaczego nie 0, 1, 2? Bo var ma zakres funkcyjny - wszystkie trzy funkcje closure odwołują się do tej samej zmiennej i, która po zakończeniu pętli ma wartość 3.

Jak działa hoisting w JavaScript?

Hoisting to mechanizm przenoszący deklaracje zmiennych i funkcji na początek ich zakresu podczas fazy kompilacji. Kluczowe jest rozróżnienie między deklaracją a inicjalizacją - hoistowane są tylko deklaracje.

Dla var oznacza to, że zmienna istnieje od początku funkcji z wartością undefined. Dla let i const deklaracja jest podniesiona, ale zmienna pozostaje w 'temporal dead zone' do momentu definicji - próba dostępu rzuca ReferenceError.

console.log(a);  // undefined (nie błąd!)
var a = 5;

console.log(b);  // ReferenceError: Cannot access 'b' before initialization
let b = 10;

// Funkcje deklarowane są hoistowane w całości
greet();  // "Hello!" - działa!

function greet() {
    console.log("Hello!");
}

// Wyrażenia funkcyjne zachowują się jak zmienne
greet2();  // TypeError: greet2 is not a function

var greet2 = function() {
    console.log("Hello!");
};

Temporal Dead Zone (TDZ): Okres między hoistingiem deklaracji let/const a jej inicjalizacją, w którym zmienna nie jest dostępna.

Jaka jest różnica między == a === w JavaScript?

Operator == (loose equality) porównuje wartości po konwersji typów, podczas gdy === (strict equality) porównuje zarówno wartość jak i typ bez konwersji. Ta różnica może prowadzić do nieoczekiwanych rezultatów i dlatego zawsze zaleca się używanie ===.

Jedyny uzasadniony przypadek użycia == to sprawdzenie czy wartość jest null lub undefined jednocześnie: x == null jest równoważne x === null || x === undefined.

Wyrażenie == === Dlaczego?
1 == '1' true false String konwertowany do Number
0 == false true false Boolean konwertowany do Number
null == undefined true false Specjalna reguła w specyfikacji
NaN == NaN false false NaN nie jest równe niczemu!
[] == false true false [] → '' → 0, false → 0
[] == ![] true false ![] to false, [] to 0

Ten ostatni przypadek ([] == ![] zwracające true) często zaskakuje: ![] to false (bo tablica jest truthy), następnie [] == false konwertuje obie strony do 0.


Asynchroniczność i Event Loop Pytania

Asynchroniczność to serce JavaScript w przeglądarce i Node.js. Te pytania sprawdzają zrozumienie mechanizmów zarządzania operacjami asynchronicznymi.

Czym różni się Promise od async/await?

Promise to obiekt reprezentujący przyszły wynik operacji asynchronicznej - może być w stanie pending (oczekujący), fulfilled (rozwiązany) lub rejected (odrzucony). Async/await to składnia zbudowana na Promise, która pozwala pisać kod asynchroniczny w sposób przypominający kod synchroniczny.

Funkcja oznaczona jako async zawsze zwraca Promise. Słowo kluczowe await wstrzymuje wykonanie funkcji do momentu rozwiązania Promise, ale nie blokuje głównego wątku - inne operacje mogą być wykonywane równolegle.

// Promise - tradycyjna składnia
function fetchUser(id) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (id > 0) {
                resolve({ id, name: 'User ' + id });
            } else {
                reject(new Error('Invalid ID'));
            }
        }, 1000);
    });
}

// Użycie z .then/.catch
fetchUser(1)
    .then(user => console.log(user))
    .catch(error => console.error(error));

// To samo z async/await
async function getUser(id) {
    try {
        const user = await fetchUser(id);
        console.log(user);
    } catch (error) {
        console.error(error);
    }
}

Równoległe vs sekwencyjne wywołania:

// ZŁE - sekwencyjne, wolne (2s łącznie)
async function slow() {
    const user = await fetchUser(1);      // czeka 1s
    const posts = await fetchPosts(1);    // czeka kolejną 1s
    return { user, posts };
}

// DOBRE - równoległe, szybkie (1s łącznie)
async function fast() {
    const [user, posts] = await Promise.all([
        fetchUser(1),
        fetchPosts(1)
    ]);
    return { user, posts };
}

Co to jest Event Loop i jak działa w JavaScript?

Event Loop to mechanizm zarządzający wykonaniem kodu w jednowątkowym JavaScript. Umożliwia asynchroniczność bez blokowania głównego wątku poprzez delegowanie operacji I/O do systemu i obsługę wyników przez callbacki.

Event Loop działa w nieskończonej pętli, przetwarzając zadania w określonej kolejności: najpierw wykonuje synchroniczny kod z call stack, następnie wszystkie microtasks (Promise callbacks, queueMicrotask), a potem jeden macrotask (setTimeout, setInterval, I/O).

while (true) {
    1. Wykonaj wszystko z Call Stack (synchroniczny kod)
    2. Wykonaj WSZYSTKIE microtasks (Promise.then, queueMicrotask)
    3. Opcjonalnie: Renderuj UI (co ~16ms)
    4. Weź JEDEN task z Task Queue (setTimeout, setInterval, I/O)
    5. Wróć do kroku 1
}

Przykład kolejności wykonania:

console.log('1');

setTimeout(() => console.log('2'), 0);

Promise.resolve().then(() => console.log('3'));

console.log('4');

// Wypisuje: 1, 4, 3, 2

Dlaczego nie 1, 4, 2, 3? Bo Promise callbacks (microtasks) mają wyższy priorytet niż setTimeout callbacks (macrotasks).

Jak działa słowo kluczowe this w JavaScript?

Wartość this w JavaScript nie jest ustalana przy definicji funkcji, lecz przy jej wywołaniu. To fundamentalna różnica w stosunku do innych języków programowania. Kontekst this zależy od sposobu wywołania funkcji i może być różny dla tej samej funkcji w różnych sytuacjach.

Istnieje pięć głównych kontekstów określających wartość this: metoda obiektu, zwykła funkcja, funkcja strzałkowa, konstruktor (z new) oraz jawne ustawienie przez call, apply lub bind.

// 1. Metoda obiektu - this to obiekt
const user = {
    name: 'Anna',
    greet() {
        console.log(`Hello, ${this.name}`);
    }
};
user.greet();  // "Hello, Anna"

// 2. Zwykła funkcja - this to window (lub undefined w strict mode)
function showThis() {
    console.log(this);
}
showThis();  // Window {...} lub undefined

// 3. Funkcja strzałkowa - this z zakresu zewnętrznego
const user2 = {
    name: 'Bartek',
    greet: () => {
        console.log(this.name);  // this to Window, nie user2!
    },
    greetDelayed() {
        setTimeout(() => {
            console.log(this.name);  // this to user2 - dziedziczone!
        }, 100);
    }
};

// 4. Konstruktor (new) - this to nowy obiekt
function Person(name) {
    this.name = name;
}
const person = new Person('Celina');

// 5. call/apply/bind - this ustawione jawnie
function introduce() {
    console.log(`I'm ${this.name}`);
}
const dev = { name: 'Developer' };
introduce.call(dev);  // "I'm Developer"

Klasyczny problem zagubionego kontekstu:

const user = {
    name: 'Anna',
    greet() {
        console.log(`Hello, ${this.name}`);
    }
};

const greetFn = user.greet;
greetFn();  // "Hello, undefined" - kontekst został utracony!

// Rozwiązanie z bind
const boundGreet = user.greet.bind(user);
boundGreet();  // "Hello, Anna"

Obiekty i Prototypy Pytania

JavaScript wykorzystuje prototypowe dziedziczenie zamiast klasowego. Te pytania sprawdzają zrozumienie mechanizmów obiektowych.

Jak działa dziedziczenie prototypowe w JavaScript?

Dziedziczenie prototypowe to mechanizm, w którym obiekty dziedziczą właściwości i metody przez łańcuch prototypów. Każdy obiekt ma ukrytą właściwość [[Prototype]] (dostępną przez __proto__ lub Object.getPrototypeOf()) wskazującą na inny obiekt.

Gdy JavaScript szuka właściwości obiektu, sprawdza najpierw sam obiekt, potem jego prototyp, następnie prototyp prototypu, aż do Object.prototype, a na końcu null. Ten proces nazywany jest prototype chain lookup.

// Każda funkcja ma właściwość prototype
function Animal(name) {
    this.name = name;
}
Animal.prototype.speak = function() {
    console.log(`${this.name} makes a sound`);
};

const dog = new Animal('Rex');
dog.speak();  // "Rex makes a sound"

// dog nie ma metody speak - jest ona w Animal.prototype
console.log(dog.hasOwnProperty('speak'));  // false
console.log(dog.hasOwnProperty('name'));   // true

// Łańcuch: dog → Animal.prototype → Object.prototype → null
console.log(Object.getPrototypeOf(dog) === Animal.prototype);  // true

Klasy ES6 to składniowy cukier na prototypy:

class Animal {
    constructor(name) {
        this.name = name;
    }
    speak() {
        console.log(`${this.name} makes a sound`);
    }
}

// Pod spodem nadal prototypy!
console.log(typeof Animal);  // "function"
console.log(Animal.prototype.speak);  // [Function: speak]

Jaka jest różnica między typami wartościowymi a referencyjnymi?

W JavaScript typy prymitywne (number, string, boolean, null, undefined, symbol, bigint) są przekazywane i przypisywane przez wartość - tworzona jest kopia wartości. Typy referencyjne (obiekty, tablice, funkcje) są przekazywane przez referencję - kopiowana jest tylko referencja do tego samego miejsca w pamięci.

Ta różnica ma fundamentalne znaczenie dla zrozumienia jak JavaScript zarządza pamięcią i jak zachowują się zmienne podczas przypisania czy przekazywania do funkcji.

// Prymitywy - kopiowanie wartości
let a = 5;
let b = a;
b = 10;
console.log(a);  // 5 - niezmienione

// Obiekty - kopiowanie referencji
let obj1 = { value: 5 };
let obj2 = obj1;
obj2.value = 10;
console.log(obj1.value);  // 10 - zmienione!

// Porównanie obiektów
let obj3 = { a: 1 };
let obj4 = { a: 1 };
console.log(obj3 === obj4);  // false - różne referencje
console.log(obj3 === obj3);  // true - ta sama referencja

Kopiowanie obiektów:

// Shallow copy - płytkie kopiowanie
let obj1 = { a: 1, nested: { b: 2 } };
let obj2 = { ...obj1 };           // Spread operator
let obj3 = Object.assign({}, obj1);  // Object.assign

// Deep copy - głębokie kopiowanie
let obj4 = JSON.parse(JSON.stringify(obj1));  // Uwaga: gubi funkcje i daty
let obj5 = structuredClone(obj1);  // Nowoczesne przeglądarki

Czym różni się Object.freeze() od Object.seal() od const?

Te trzy mechanizmy oferują różne poziomy ochrony przed modyfikacją, ale działają na różnych poziomach. const chroni binding zmiennej (nie można jej przepisać), Object.seal() chroni strukturę obiektu (nie można dodawać/usuwać właściwości), a Object.freeze() zapewnia pełną niezmienność obiektu.

Wszystkie te mechanizmy działają płytko - chronią tylko pierwszy poziom zagnieżdżenia. Aby uzyskać głęboką ochronę, należy zastosować je rekurencyjnie.

// const - tylko binding zmiennej
const obj1 = { a: 1 };
obj1.a = 2;      // OK - można modyfikować właściwości
obj1.b = 3;      // OK - można dodawać właściwości
// obj1 = {};    // TypeError - nie można przepisać zmiennej

// Object.seal - struktura zamknięta, wartości modyfikowalne
const obj2 = { a: 1 };
Object.seal(obj2);
obj2.a = 2;      // OK - można modyfikować istniejące właściwości
obj2.b = 3;      // Ignorowane (lub TypeError w strict mode)
delete obj2.a;   // Ignorowane - nie można usuwać

// Object.freeze - całkowicie zamrożony
const obj3 = { a: 1 };
Object.freeze(obj3);
obj3.a = 2;      // Ignorowane - nie można modyfikować
obj3.b = 3;      // Ignorowane - nie można dodawać

console.log(Object.isSealed(obj2));   // true
console.log(Object.isFrozen(obj3));   // true

Uwaga na zagnieżdżenie:

const obj = { nested: { a: 1 } };
Object.freeze(obj);
obj.nested.a = 2;  // OK - zagnieżdżony obiekt nie jest zamrożony!

Składnia i Operatory Pytania

Te pytania sprawdzają znajomość nowoczesnej składni JavaScript i zrozumienie jak działają różne operatory.

Jaka jest różnica między spread a rest operator?

Chociaż oba używają tej samej składni (...), spread i rest operator mają przeciwne działanie. Spread 'rozpyla' elementy kolekcji (tablicy, obiektu) na indywidualne elementy, podczas gdy rest 'zbiera' wiele elementów w jedną kolekcję.

Spread używamy do kopiowania, łączenia struktur danych i przekazywania argumentów. Rest używamy w destrukturyzacji i definicjach funkcji z zmienną liczbą parametrów.

// SPREAD - rozpyla elementy
const arr = [1, 2, 3];
const copy = [...arr];  // [1, 2, 3]
const merged = [...arr, 4, 5, ...arr];  // [1,2,3,4,5,1,2,3]

// Kopiowanie obiektu z modyfikacją
const user = { name: 'Anna', age: 25 };
const userCopy = { ...user, age: 26 };  // { name: 'Anna', age: 26 }

// Argumenty funkcji
const numbers = [1, 2, 3];
console.log(Math.max(...numbers));  // 3
// REST - zbiera elementy
// W parametrach funkcji
function sum(...numbers) {
    return numbers.reduce((a, b) => a + b, 0);
}
sum(1, 2, 3, 4);  // 10 - wszystkie argumenty w tablicy 'numbers'

// W destrukturyzacji tablicy
const [first, second, ...rest] = [1, 2, 3, 4, 5];
// first = 1, second = 2, rest = [3, 4, 5]

// W destrukturyzacji obiektu
const { name, ...others } = { name: 'Anna', age: 25, city: 'Warsaw' };
// name = 'Anna', others = { age: 25, city: 'Warsaw' }

Czym różnią się var, let i const?

Te trzy słowa kluczowe różnią się zakresem (scope), hoistingiem, możliwością re-deklaracji i re-przypisania. var to starszy mechanizm z wieloma quirk'ami, let i const to nowoczesne, bezpieczniejsze alternatywy wprowadzone w ES6.

Kluczowa różnica to zakres: var ma zakres funkcyjny (function scope), podczas gdy let i const mają zakres blokowy (block scope). Dodatkowo var pozwala na re-deklarację, co może prowadzić do błędów.

// var - function scope
function example() {
    if (true) {
        var x = 1;
    }
    console.log(x);  // 1 - dostępne poza blokiem!
}

// let - block scope
function example2() {
    if (true) {
        let y = 1;
    }
    console.log(y);  // ReferenceError - niedostępne poza blokiem
}

// const - nie można re-przypisać, ale można modyfikować zawartość
const obj = { a: 1 };
obj.a = 2;          // OK - modyfikacja właściwości
// obj = { b: 2 };  // TypeError - re-przypisanie

const arr = [1, 2, 3];
arr.push(4);        // OK - modyfikacja zawartości
// arr = [];        // TypeError - re-przypisanie

Re-deklaracja:

// var pozwala na re-deklarację
var a = 1;
var a = 2;  // OK

// let nie pozwala
let b = 1;
// let b = 2;  // SyntaxError: Identifier 'b' has already been declared

Jak działa destructuring w JavaScript?

Destructuring to składnia pozwalająca wyciągać wartości z tablic i obiektów bezpośrednio do zmiennych. Obsługuje wartości domyślne, zmianę nazw zmiennych, zagnieżdżenie i rest operator. Jest szczególnie przydatny w funkcjach do tworzenia nazwanych parametrów.

Mechanizm ten znacznie upraszcza kod i czyni go bardziej czytelnym, eliminując potrzebę wielokrotnego odwoływania się do właściwości obiektów czy elementów tablic.

// Podstawowe destructuring obiektu
const user = { name: 'Anna', age: 25, city: 'Warsaw' };
const { name, age } = user;
// name = 'Anna', age = 25

// Wartości domyślne
const { name: userName = 'Anonymous', role = 'user' } = user;
// userName = 'Anna', role = 'user' (domyślna)

// Zagnieżdżenie
const { address: { city, street } } = { 
    address: { city: 'Warsaw', street: 'Main St' } 
};
// city = 'Warsaw', street = 'Main St'

// Destructuring tablicy
const numbers = [1, 2, 3, 4, 5];
const [first, second, ...rest] = numbers;
// first = 1, second = 2, rest = [3, 4, 5]

// Pomijanie elementów
const [, , third] = numbers;  // third = 3

W parametrach funkcji:

function createUser({ name, age = 18, role = 'user' } = {}) {
    return { name, age, role };
}

createUser({ name: 'Anna' });  // { name: 'Anna', age: 18, role: 'user' }
createUser();                   // { name: undefined, age: 18, role: 'user' }

// Zamiana wartości bez zmiennej tymczasowej
let a = 1, b = 2;
[a, b] = [b, a];  // a = 2, b = 1

Funkcje i Zasięg Pytania

Te pytania sprawdzają zrozumienie różnych typów funkcji i mechanizmów zarządzania zasięgiem w JavaScript.

Czym różnią się funkcje strzałkowe od zwykłych funkcji?

Funkcje strzałkowe wprowadzone w ES6 to więcej niż tylko krótsza składnia. Mają fundamentalne różnice w zachowaniu: nie posiadają własnego this, arguments, super ani new.target - wszystko dziedziczą z zakresu zewnętrznego. Nie można ich używać jako konstruktorów ani nie mają właściwości prototype.

Te różnice czynią je idealnymi do callbacków i krótkich wyrażeń, ale nieodpowiednimi jako metody obiektów czy konstruktory. Wybór między funkcją strzałkową a zwykłą powinien być świadomy i oparty na potrzebach kontekstowych.

// Strzałkowa w callbacku - idealna
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2);

// Strzałkowa zachowuje this z zakresu zewnętrznego
const obj = {
    name: 'Anna',
    greetLater() {
        setTimeout(() => {
            console.log(this.name);  // 'Anna' - this z greetLater
        }, 100);
    }
};

// ❌ Strzałkowa jako metoda - ZŁE
const user = {
    name: 'Anna',
    greet: () => console.log(this.name)  // undefined! this to Window
};

// ❌ Strzałkowa jako konstruktor - BŁĄD
const Person = (name) => { this.name = name; };
// new Person('Anna');  // TypeError: Person is not a constructor

Brak obiektu arguments:

// Zwykła funkcja ma arguments
function regular() {
    console.log(arguments);  // [Arguments] { '0': 1, '1': 2 }
}
regular(1, 2);

// Strzałkowa nie ma - użyj rest parameters
const arrow = (...args) => {
    console.log(args);  // [1, 2]
};
arrow(1, 2);

Jaka jest różnica między null a undefined?

Zarówno null jak i undefined reprezentują 'brak wartości', ale mają różne znaczenia semantyczne. undefined oznacza, że zmienna została zadeklarowana ale nie zainicjalizowana, lub że właściwość obiektu nie istnieje. null to jawne przypisanie 'brak wartości' przez programistę - wyraża intencję.

Ta różnica jest ważna dla czytelności kodu i debugging. Gdy widzisz undefined, zazwyczaj oznacza to problem z kodem lub brak inicjalizacji. null to świadoma decyzja programisty.

// undefined - brak inicjalizacji
let x;
console.log(x);  // undefined

// undefined - brak właściwości
const obj = {};
console.log(obj.name);  // undefined

// undefined - brak argumentu
function greet(name) {
    console.log(name);
}
greet();  // undefined

// null - jawnie brak wartości
const user = {
    name: 'Anna',
    manager: null  // jawnie: nie ma managera
};

// API często zwraca null dla pustych wyników
const result = document.getElementById('nonexistent');  // null

Porównania:

console.log(null == undefined);   // true - loose equality
console.log(null === undefined);  // false - strict equality

// Sprawdzanie obu naraz
if (value == null) {
    // value jest null LUB undefined
}

// typeof quirk
console.log(typeof undefined);  // "undefined"
console.log(typeof null);       // "object" - historyczny błąd JS!

Jak działają metody tablicowe map, filter, reduce?

Te metody to fundament programowania funkcyjnego w JavaScript. Żadna z nich nie modyfikuje oryginalnej tablicy - wszystkie zwracają nowe wartości. map transformuje każdy element według podanej funkcji, filter wybiera elementy spełniające warunek, a reduce akumuluje tablicę do jednej wartości.

Zrozumienie tych metod i umiejętność ich łączenia w łańcuchy jest kluczowe dla pisania czystego, funkcjonalnego kodu JavaScript. Rekruterzy często proszą o implementację jednej z tych metod od podstaw.

const users = [
    { name: 'Anna', age: 25, active: true },
    { name: 'Bartek', age: 30, active: false },
    { name: 'Celina', age: 28, active: true }
];

// map - transformacja każdego elementu
const names = users.map(u => u.name);
// ['Anna', 'Bartek', 'Celina']

// filter - selekcja elementów
const activeUsers = users.filter(u => u.active);
// [{ name: 'Anna', ... }, { name: 'Celina', ... }]

// reduce - akumulacja do jednej wartości
const totalAge = users.reduce((sum, u) => sum + u.age, 0);
// 83

// Łączenie metod w łańcuch
const activeUserNames = users
    .filter(u => u.active)
    .map(u => u.name.toUpperCase());
// ['ANNA', 'CELINA']

Implementacja reduce od podstaw:

function myReduce(array, callback, initialValue) {
    let accumulator = initialValue !== undefined ? initialValue : array[0];
    let startIndex = initialValue !== undefined ? 0 : 1;

    for (let i = startIndex; i < array.length; i++) {
        accumulator = callback(accumulator, array[i], i, array);
    }

    return accumulator;
}

// Test
const sum = myReduce([1, 2, 3, 4], (acc, val) => acc + val, 0);
console.log(sum);  // 10

Dodatkowe metody:

// find - pierwszy pasujący element
const bartek = users.find(u => u.name === 'Bartek');
// { name: 'Bartek', age: 30, active: false }

// some - czy którykolwiek spełnia warunek
const hasInactive = users.some(u => !u.active);  // true

// every - czy wszystkie spełniają warunek
const allActive = users.every(u => u.active);  // false

// indexOf vs findIndex
const ages = [25, 30, 28];
console.log(ages.indexOf(30));  // 1 - szuka wartości
console.log(users.findIndex(u => u.age === 30));  // 1 - szuka według funkcji

Powiązane Artykuły

Ostatnia aktualizacja: Styczeń 2026

Chcesz więcej pytań rekrutacyjnych?

To tylko jeden temat z naszego kompletnego przewodnika po rozmowach rekrutacyjnych. Uzyskaj dostęp do 800+ pytań z 13 technologii.

Kup pełny dostęp Zobacz bezpłatny podgląd
Powrót do blogu

Zostaw komentarz

Pamiętaj, że komentarze muszą zostać zatwierdzone przed ich opublikowaniem.