modul 00 / start: ce este javascript
javascript & locul lui în web
Ai învățat structura (HTML) și prezentarea (CSS). JavaScript e al treilea strat: comportamentul. E limbajul care face paginile să reacționeze — să răspundă la click, să valideze formulare, să încarce date fără reîncărcare, să animeze, să calculeze. HTML e scheletul, CSS sunt hainele, JS sunt mușchii.
ce poate face js în browser
- Reacționează la utilizator — click, tastare, scroll, mișcarea mouse-ului (evenimente).
- Modifică pagina live — schimbă text, adaugă/șterge elemente, comută clase CSS (manipularea DOM).
- Comunică cu servere — aduce și trimite date fără să reîncarce pagina (fetch, API-uri).
- Ține stare și logică — coșuri de cumpărături, jocuri, calcule, validări.
js nu e java
Numele e o coincidență istorică de marketing din 1995. JavaScript și Java sunt limbaje complet diferite — ca „car” și „carpet”. Numele tehnic al standardului e ECMAScript (de aici „ES6”, „ES2015” etc.): un standard viu, cu o versiune nouă în fiecare an.
unde rulează js
| Mediu | Ce înseamnă |
| Browser | Mediul original: fiecare browser are un motor JS (V8 în Chrome, SpiderMonkey în Firefox). Aici controlează pagina. |
| Node.js | JS pe server/în terminal (același motor V8, în afara browserului): backend, unelte, scripturi. |
| Peste tot | Aplicații desktop (Electron), mobile (React Native), chiar embedded. JS a ieșit demult din browser. |
Cursul acesta se concentrează pe JavaScript în browser — limbajul de bază + interacțiunea cu pagina (DOM). Fundamentele sunt identice oriunde ai rula JS mai târziu.
mindset
JS e un limbaj de programare real — variabile, logică, funcții, structuri de date. Spre deosebire de HTML/CSS (descriptive), aici gândești algoritmic: pas cu pas, condiții, repetiții. E saltul de la „a descrie o pagină” la „a rezolva o problemă”. Cursul e construit pe înțelegerea mecanismelor, nu pe memorarea sintaxei.
modul 00 / start: ce este javascript
unde scrii js, consola & primul script
cele trei moduri de a adăuga js
| Mod | Cum | Verdict |
| Extern | <script src="app.js"></script> | Standardul. Fișier separat, cache-uit, refolosibil |
| Intern | <script>…cod…</script> în HTML | Experimente, pagini mici |
| Inline (pe atribut) | <button onclick="…"> | De evitat — amestecă structura cu logica |
unde pui <script> și de ce contează
<head>
<script src="app.js" defer></script> ← modern: în head cu defer
</head>
- defer — scriptul se descarcă în paralel cu HTML-ul, dar rulează DUPĂ ce pagina e complet parsată. Așa ai acces la toate elementele și nu blochezi randarea. Soluția modernă curată.
- Fără defer, un <script> în head rulează înainte ca elementele să existe → „Cannot read property of null” (elementul căutat nu s-a creat încă). Vechea soluție era scriptul înainte de </body>; azi preferi defer.
consola — laboratorul tău
DevTools (F12) → tab-ul Console: aici rulezi JS live, vezi erorile și afișezi valori. E cel mai folosit instrument al unui dezvoltator JS.
console.log("Salut!"); // afișează în consolă
console.log(2 + 2); // 4
console.warn("atenție"); // avertisment (galben)
console.error("eroare"); // eroare (roșu)
console.table(arr); // afișează tabelar
console.log() e prietenul tău de-o viață: afișezi orice valoare ca să înțelegi ce se întâmplă în cod. „Printf debugging” — verifici realitatea în loc s-o presupui.
primul script
// app.js
const nume = "Romeo";
console.log("Salut, " + nume + "!");
document.body.style.background = "#0B0E11";
alert("Pagina a fost modificată de JS!");
- // — comentariu pe o linie; /* … */ — pe mai multe.
- ; la finalul instrucțiunilor — recomandat pentru claritate (JS le inserează automat, dar bazarea pe asta produce capcane rare).
- JS e case-sensitive: nume ≠ Nume.
reflex de la prima zi
Când nu înțelegi ce face codul: console.log() pe valorile suspecte. Când apare o eroare: citește-o în Console — spune tipul erorii, fișierul și linia. Programarea nu e „să știi tot pe de rost”, ci să investighezi metodic. Consola e locul unde faci asta.
modul 01 / variabile, tipuri & operatori
variabile: let, const & var
O variabilă e un nume dat unei valori — o „cutie etichetată” în care ții date ca să le folosești și să le modifici. E conceptul fundamental al oricărei programări.
cele trei cuvinte-cheie (și care se folosește)
const varsta = 25; // valoare care NU se reatribuie
let scor = 0; // valoare care se va schimba
scor = 10; // ok
var vechi = "…"; // stilul vechi — de evitat în cod nou
| Cuvânt | Reatribuire | Scope (domeniu) | Folosire |
| const | NU | De bloc { } | Implicit — folosește-l mereu întâi |
| let | DA | De bloc { } | Doar când chiar reatribui valoarea |
| var | DA | De funcție (capcane) | Evită — moștenire istorică |
regula de aur: const by default
Începe fiecare variabilă cu const. Dacă ai nevoie s-o reatribui, schimbi în let. Așa comunici intenția și previi reatribuiri accidentale. var are un scope confuz (de funcție, nu de bloc) și „hoisting” înșelător — în cod modern nu-l mai folosești.
const nu înseamnă „înghețat”
const oprește reatribuirea variabilei, dar dacă valoarea e un obiect sau array, conținutul lui se poate modifica: const lista = []; lista.push(1); e perfect valid. const leagă numele de valoare, nu îngheață valoarea în sine.
denumirea variabilelor
- camelCase — convenția JS: numeUtilizator, totalPret.
- Nume descriptive: const d nu spune nimic; const dataNasterii spune tot. Codul se citește de 10× mai des decât se scrie.
- Nu pot începe cu cifră; permise litere, cifre, _ și $. Case-sensitive.
modul 01 / variabile, tipuri & operatori
tipuri de date primitive
JS are câteva tipuri de date primitive — cărămizile din care se construiește totul. JS e dinamic tipat: nu declari tipul, îl deduce din valoare, iar o variabilă poate primi apoi alt tip (deși e bine să eviți asta).
| Tip | Exemplu | Ce e |
| string | "text", 'text', `text` | Text; ghilimele simple, duble sau backticks |
| number | 42, 3.14, -7 | Un singur tip pentru întregi ȘI zecimale |
| boolean | true, false | Adevărat/fals — baza logicii |
| undefined | undefined | Variabilă declarată dar fără valoare atribuită |
| null | null | „Nimic” intenționat — absență deliberată a valorii |
| bigint / symbol | 10n / Symbol() | Numere uriașe / identificatori unici (avansat) |
Restul (array-uri, obiecte, funcții) sunt obiecte — le vezi în modulele următoare. typeof valoare îți spune tipul: typeof "hi" → "string".
undefined vs null — distincția
- undefined — JS spune „n-am nicio valoare aici” (variabilă neatribuită, proprietate inexistentă). Sistemul o pune.
- null — TU spui „aici e intenționat nimic” (ex: un utilizator care nu s-a logat încă). Programatorul o pune.
template literals — construcția modernă de text
const nume = "Ana";
const varsta = 30;
// vechi (concatenare):
"Salut " + nume + ", ai " + varsta + " ani"
// modern (template literal cu backticks):
`Salut ${nume}, ai ${varsta} ani`
- Backticks ` ` + ${…} pentru a insera valori/expresii direct în text.
- Permit și text pe mai multe rânduri fără trucuri. Standardul modern — mai lizibil decât concatenarea cu +.
conversii de tip
Convertești explicit: Number("42") → 42, String(42) → "42", Boolean(0) → false. „42” (string, de la un input) + 8 dă „428”, nu 50 — capcana clasică a datelor din formulare. Convertește input-urile la number înainte de calcule.
modul 01 / variabile, tipuri & operatori
operatori: aritmetici, comparație & logici
aritmetici
+ - * / // adunare, scădere, înmulțire, împărțire
% // modulo — restul împărțirii (7 % 3 = 1)
** // putere (2 ** 3 = 8)
++ -- // incrementare / decrementare (scor++)
% (modulo) e surprinzător de util: n % 2 === 0 testează dacă n e par; i % lungime creează cicluri.
atribuire compusă
scor += 10; // scor = scor + 10 (și -=, *=, /=)
comparație — atenție la === vs ==
| Operator | Ce face |
| === | Egalitate strictă: valoare ȘI tip. Folosește MEREU ăsta |
| == | Egalitate „slabă”: convertește tipurile întâi — sursă de bug-uri |
| !== / != | Diferit (strict / slab) |
| < > <= >= | Mai mic / mare / sau egal |
De ce === mereu: 0 == "" e true (ambele devin fals după conversie!), dar 0 === "" e false (tipuri diferite — corect). == ascunde bug-uri prin conversii surprinzătoare; === compară cinstit. Regula profesionistului: mereu ===.
logici
&& // ȘI — true doar dacă AMBELE sunt true
|| // SAU — true dacă MĂCAR UNA e true
! // NU — inversează (!true = false)
- Se combină cu comparațiile: varsta >= 18 && areBilet.
- Short-circuit: && se oprește la primul fals, || la primul adevărat — folosit pentru valori implicite și execuție condiționată.
- Truthy / falsy: în context boolean, valorile „falsy” sunt false, 0, "", null, undefined, NaN; restul sunt „truthy”. De aici if (nume) = „dacă nume are conținut”.
operatori moderni utili
const x = valoare ?? "implicit"; // nullish: "implicit" doar dacă valoare e null/undefined
const nume = user?.profil?.nume; // optional chaining: nu crapă dacă profil lipsește
capcana clasică
NaN (Not a Number) apare din operații numerice invalide ("abc" * 2). Ciudat: NaN === NaN e false — verifici cu Number.isNaN(x). Iar 0.1 + 0.2 nu dă exact 0.3 (aritmetică în virgulă mobilă) — normal în orice limbaj, nu un bug JS.
modul 02 / string-uri & numere
lucrul cu string-uri
Textul e peste tot: nume, mesaje, input-uri, URL-uri. String-urile au zeci de metode utile; iată-le pe cele pe care le folosești zilnic.
proprietăți & acces
const s = "JavaScript";
s.length // 10 — numărul de caractere
s[0] // "J" — caracterul de la index (de la 0!)
s[s.length - 1] // "t" — ultimul caracter
Indexarea de la 0 e universală în programare: primul element e la poziția 0, ultimul la length−1.
metode esențiale
| Metodă | Ce face | Exemplu → rezultat |
| toUpperCase / toLowerCase | Schimbă mărimea literelor | "abc".toUpperCase() → "ABC" |
| trim() | Elimină spațiile de la capete | " hi ".trim() → "hi" |
| includes(x) | Conține subșirul? (true/false) | "salut".includes("al") → true |
| indexOf(x) | Poziția primei apariții (−1 dacă lipsește) | "salut".indexOf("l") → 2 |
| slice(a, b) | Extrage o porțiune (de la a la b, exclusiv) | "JavaScript".slice(0, 4) → "Java" |
| replace(a, b) | Înlocuiește (replaceAll pentru toate) | "a-b-c".replaceAll("-", " ") → "a b c" |
| split(sep) | Sparge în array după separator | "a,b,c".split(",") → ["a","b","c"] |
| startsWith / endsWith | Începe/se termină cu? | "foto.jpg".endsWith(".jpg") → true |
| padStart(n, "0") | Completează la lungime | "5".padStart(2, "0") → "05" |
string-urile sunt imutabile
Metodele NU modifică string-ul original — returnează unul nou. s.toUpperCase() nu schimbă s; trebuie să atribui rezultatul: const mare = s.toUpperCase(). Capcană frecventă: „am apelat trim() dar tot are spații” — pentru că n-ai folosit valoarea returnată.
înlănțuirea metodelor
Fiindcă fiecare metodă returnează un string, le poți înlănțui: " Salut Lume ".trim().toLowerCase().replaceAll(" ", "-") → "salut-lume" (exact cum generezi un slug de URL). Fiecare pas transformă rezultatul precedentului.
modul 02 / string-uri & numere
numere, conversii & obiectul Math
un singur tip number
JS nu separă întregii de zecimale — totul e number (virgulă mobilă pe 64 de biți). Simplu, dar cu o consecință: 0.1 + 0.2 === 0.30000000000000004. Nu e bug — e cum funcționează aritmetica binară în orice limbaj. Pentru bani, lucrezi în cenți (întregi) sau rotunjești la afișare.
conversii string ↔ number
Number("42") // 42 (strict — "42a" → NaN)
parseInt("42px") // 42 (citește cât poate de la început)
parseFloat("3.14m") // 3.14
(42).toString() // "42"
(3.14159).toFixed(2) // "3.14" — string cu 2 zecimale (rotunjit)
+"42" // 42 — trucul "+" unar convertește la number
- Number() e strict (orice caracter nenumeric → NaN); parseInt/parseFloat sunt tolerante (citesc prefixul numeric) — utile pentru „16px”.
- toFixed(n) returnează un string cu n zecimale — perfect pentru afișarea prețurilor, dar convertește înapoi la number dacă mai calculezi.
obiectul Math
| Funcție | Ce face | Exemplu |
| Math.round(x) | Rotunjește la cel mai apropiat întreg | Math.round(2.5) → 3 |
| Math.floor / ceil | Rotunjește în jos / în sus | Math.floor(2.9) → 2 |
| Math.max / min | Cea mai mare / mică valoare | Math.max(3, 7, 2) → 7 |
| Math.abs(x) | Valoarea absolută | Math.abs(-5) → 5 |
| Math.random() | Număr aleator în [0, 1) | 0.734… |
| Math.sqrt / pow | Radical / putere | Math.sqrt(9) → 3 |
numărul aleator într-un interval — rețeta
// întreg aleator între min și max (inclusiv):
Math.floor(Math.random() * (max - min + 1)) + min
// zar (1–6):
Math.floor(Math.random() * 6) + 1
verificarea numerelor
Number.isNaN(x) — testează dacă e NaN (rezultatul unei operații numerice invalide). Number.isInteger(x) — dacă e întreg. Iar la validarea input-urilor: convertești cu Number(), apoi verifici cu isNaN înainte de a folosi valoarea. Datele de la utilizator nu sunt niciodată de încredere ca numere.
modul 03 / control flow: decizii & bucle
condiționale: if, else, ternar & switch
Programele iau decizii: „dacă e logat, arată profilul; altfel, arată butonul de login”. Control flow-ul e ce transformă o listă de instrucțiuni într-un program care gândește.
if / else if / else
if (scor >= 90) {
nota = "excelent";
} else if (scor >= 70) {
nota = "bine";
} else {
nota = "de îmbunătățit";
}
- Condiția din ( ) se evaluează la boolean (sau truthy/falsy).
- Se verifică de sus în jos: prima condiție adevărată câștigă, restul se sar. Ordinea contează.
- Combină condiții cu && și ||: if (varsta >= 18 && areCont).
operatorul ternar — if scurt pentru o valoare
condiție ? valoareDacăTrue : valoareDacăFalse
const mesaj = varsta >= 18 ? "acces permis" : "acces refuzat";
const eticheta = `${nr} ${nr === 1 ? "element" : "elemente"}`;
Perfect când alegi între două valori. Nu-l imbrica adânc — trei ternari cuibăriți sunt ilizibili; acolo revii la if/else.
switch — multe cazuri pe aceeași valoare
switch (zi) {
case "sâmbătă":
case "duminică":
tip = "weekend";
break;
default:
tip = "zi lucrătoare";
}
- Compară o valoare cu mai multe cazuri; break oprește (fără el, „cade” în cazul următor — util deliberat pentru grupare, ca weekend-ul de mai sus).
- default = cazul „niciunul de mai sus”.
- Pentru multe ramuri pe aceeași variabilă, switch e mai lizibil decât un lanț lung de else if.
capcană
Nu confunda atribuirea = cu comparația === în condiții: if (x = 5) ATRIBUIE 5 lui x și e mereu truthy — bug tăcut. Mereu === în comparații. Multe linters te avertizează.
modul 03 / control flow: decizii & bucle
bucle: for, while & for...of
Buclele repetă cod: parcurg liste, numără, așteaptă o condiție. Fără ele, ai scrie manual aceeași linie de o mie de ori.
bucla for clasică
for (let i = 0; i < 5; i++) {
console.log(i); // 0, 1, 2, 3, 4
}
Trei părți: inițializare (let i = 0) · condiție de continuare (i < 5) · pas (i++). Controlul complet asupra numărării — când ai nevoie de index sau de un număr fix de repetări.
for...of — parcurgerea directă a valorilor
const fructe = ["măr", "pară", "prună"];
for (const fruct of fructe) {
console.log(fruct); // măr, pară, prună
}
Modern și lizibil: îți dă direct fiecare valoare, fără să te chinui cu indici. Prima alegere pentru „fă ceva cu fiecare element din listă”. (Există și for...in — dar acela dă CHEILE unui obiect; nu-l confunda cu for...of.)
while & do...while
while (conditie) { // repetă CÂT TIMP condiția e true
// ...
}
do { // rulează măcar o dată, apoi verifică
// ...
} while (conditie);
while se folosește când nu știi dinainte de câte ori repeți (aștepți o condiție). Grija #1: condiția trebuie să devină cândva false, altfel — buclă infinită (pagina îngheață).
break & continue
for (const n of numere) {
if (n < 0) continue; // SARI peste iterația asta
if (n > 100) break; // IEȘI complet din buclă
console.log(n);
}
- continue — sare la iterația următoare (ignoră restul corpului pentru elementul curent).
- break — oprește bucla complet.
for clasic vs for...of vs metode
Ai nevoie de index sau de un număr exact de pași → for clasic. Doar parcurgi valorile unei liste → for...of (mai curat). Transformi/filtrezi o listă → metodele de array (map/filter/reduce — modulul 5), care sunt adesea și mai expresive decât buclele manuale.
modul 04 / funcții
funcții: declarare, parametri & return
O funcție e un bloc de cod reutilizabil, cu un nume — o „mașinărie” care primește intrări, face ceva și dă un rezultat. Funcțiile sunt inima organizării codului: le scrii o dată, le folosești oriunde. Principiul DRY (Don't Repeat Yourself): dacă scrii de două ori același cod, fă-l funcție.
declararea & apelarea
function salut(nume) { // definire (nume = parametru)
return `Salut, ${nume}!`;
}
const mesaj = salut("Ana"); // apel ("Ana" = argument) → "Salut, Ana!"
- Parametrii — variabilele din definiție (rețeta cere „nume”); argumentele — valorile reale la apel („Ana”).
- return — trimite un rezultat înapoi și oprește funcția. Fără return, funcția returnează undefined.
- O funcție ori returnează o valoare (o calculează), ori face un efect (schimbă pagina, afișează) — ideal, nu amestecă prea mult.
parametri: valori implicite & rest
function pret(baza, tva = 0.2) { // valoare implicită
return baza * (1 + tva);
}
pret(100); // 120 (folosește tva = 0.2)
pret(100, 0.1); // 110
function suma(...numere) { // rest: adună oricâte argumente
let t = 0;
for (const n of numere) t += n;
return t;
}
suma(1, 2, 3, 4); // 10
de ce funcții
- Reutilizare — scrii logica o dată, o apelezi de câte ori vrei.
- Claritate — un nume bun (calculeazaTotal) explică intenția mai bine decât 10 linii inline.
- Testare & întreținere — repari într-un loc, se corectează peste tot.
- O funcție bună face un singur lucru, e scurtă și are un nume care spune ce face.
principiu
Funcțiile sunt cum descompui o problemă mare în bucăți gestionabile. În loc de un munte de cod, ai piese mici, fiecare cu un rol clar, care se combină. Programarea bună e, în mare parte, arta de a alege bucățile potrivite.
modul 04 / funcții
arrow functions, scope & closures
arrow functions — sintaxa modernă
// funcție clasică:
function dubla(x) { return x * 2; }
// arrow echivalentă:
const dubla = (x) => x * 2; // return implicit dacă e o singură expresie
const salut = (nume) => `Salut, ${nume}`;
const acum = () => Date.now(); // fără parametri: ()
const proceseaza = (x) => { // cu corp { }: return explicit
const y = x * 2;
return y + 1;
};
- Mai scurte; cu o singură expresie, return e implicit (fără acolade).
- Foarte folosite ca argumente pentru alte funcții (callbacks) — le vei vedea peste tot la metodele de array și la evenimente.
- Diferă de funcțiile clasice la this (arrow-ul nu-și creează propriul this) — relevant la obiecte și evenimente, modulele următoare.
scope — unde „trăiește” o variabilă
const global = "văzut peste tot";
function exemplu() {
const local = "doar în funcție";
console.log(global); // ok — funcția vede în afară
}
console.log(local); // EROARE — exteriorul nu vede înăuntru
- Scope-ul de bloc (let/const): o variabilă declarată în { } (funcție, if, buclă) există doar acolo.
- Funcțiile văд spre exterior (variabilele din jur), dar exteriorul nu vede variabilele lor interne — încapsulare.
- Ține variabilele în cel mai restrâns scope posibil — mai puține coliziuni, cod mai ușor de urmărit.
closures — funcții care „își amintesc”
function creeazaContor() {
let count = 0;
return () => {
count++;
return count;
};
}
const contor = creeazaContor();
contor(); // 1
contor(); // 2 — își „amintește” count între apeluri!
Un closure = o funcție care „ține minte” variabilele din locul unde a fost creată, chiar după ce funcția-părinte s-a terminat. Concept avansat, dar puternic: stă la baza modulelor, a stării private și a multor pattern-uri. Nu trebuie să-l stăpânești complet acum — doar să-l recunoști.
funcțiile sunt valori (first-class)
În JS, o funcție e o valoare ca oricare alta: o pui într-o variabilă, o dai ca argument altei funcții, o returnezi. De aici callbacks (dai o funcție care va fi apelată mai târziu — la un click, când sosesc date). E baza a tot ce urmează: array-uri, evenimente, cod asincron.
modul 05 / array-uri & metodele lor
array-uri: bazele
Un array e o listă ordonată de valori: nume, produse, scoruri, orice colecție. Alături de obiecte, e structura de date pe care o folosești cel mai des.
crearea & accesul
const fructe = ["măr", "pară", "prună"];
fructe[0] // "măr" (index de la 0)
fructe.length // 3
fructe[fructe.length - 1] // "prună" (ultimul)
fructe.at(-1) // "prună" (modern: index negativ = de la coadă)
Un array poate ține orice tip, chiar amestecat sau alte array-uri/obiecte. Indexarea începe de la 0.
modificarea (metode mutante)
| Metodă | Ce face |
| push(x) / pop() | Adaugă / scoate la SFÂRȘIT |
| unshift(x) / shift() | Adaugă / scoate la ÎNCEPUT |
| splice(i, n) | Scoate/inserează n elemente de la indexul i |
| indexOf(x) / includes(x) | Poziția / prezența unui element |
| join(sep) | Unește într-un string ("a,b,c") — inversul lui split |
| reverse() / sort() | Inversează / sortează (atenție: sortarea e alfabetică implicit!) |
capcana sortării numerice
[10, 2, 1].sort() // [1, 10, 2] ❌ (compară ca text!)
[10, 2, 1].sort((a, b) => a - b); // [1, 2, 10] ✓ (numeric crescător)
sort() implicit compară elementele ca string-uri („10” < „2” alfabetic). Pentru numere, dai o funcție de comparație (a, b) => a - b.
spread & destructuring
const copie = [...fructe]; // spread: copie (nu referință)
const toate = [...a, ...b]; // combină două array-uri
const [primul, alDoilea] = fructe; // destructuring: extrage în variabile
array-urile sunt referințe
const b = a NU copiază array-ul — ambele nume indică aceeași listă; modifici prin b, se schimbă și a. Pentru o copie reală: const b = [...a] (spread). Aceeași regulă la obiecte — sursă frecventă de bug-uri „misterioase”.
modul 05 / array-uri & metodele lor
metodele funcționale: map, filter, reduce, find
Aici JS devine cu adevărat expresiv. În loc să scrii bucle manuale, descrii transformarea pe care o vrei. Aceste metode primesc o funcție (un callback) și o aplică pe fiecare element. Sunt printre cele mai folosite instrumente din tot JS-ul modern.
forEach — fă ceva cu fiecare
fructe.forEach((fruct) => console.log(fruct));
Ca for...of, dar ca metodă. Doar execută (nu returnează nimic util) — pentru efecte, nu pentru transformări.
map — transformă fiecare element
const numere = [1, 2, 3];
const duble = numere.map((n) => n * 2); // [2, 4, 6]
const nume = utilizatori.map((u) => u.nume); // extrage un câmp
map creează un array NOU cu fiecare element transformat. Același număr de elemente, fiecare „prelucrat”. Îl folosești constant: transformi date brute în ce ai nevoie (ex: obiecte → HTML).
filter — păstrează doar ce trece testul
const numere = [1, 2, 3, 4, 5, 6];
const pare = numere.filter((n) => n % 2 === 0); // [2, 4, 6]
const active = comenzi.filter((c) => c.status === "activ");
filter creează un array nou doar cu elementele pentru care callback-ul returnează true. Mai puține (sau la fel de multe) elemente, niciunul modificat.
find — primul care se potrivește
const user = utilizatori.find((u) => u.id === 42); // obiectul, sau undefined
find returnează primul element care trece testul (sau undefined). Pentru „caută un anume element”.
reduce — condensează totul într-o singură valoare
const numere = [10, 20, 30];
const total = numere.reduce((acc, n) => acc + n, 0); // 60
// acc=acumulator, n=element, 0=valoare inițială
reduce „strânge” un array într-o singură valoare (sumă, produs, un obiect). Cel mai abstract, dar și cel mai puternic — orice altă metodă se poate exprima prin reduce.
înlănțuirea — puterea reală
const totalActive = comenzi
.filter((c) => c.status === "activ") // doar cele active
.map((c) => c.suma) // extrage sumele
.reduce((t, s) => t + s, 0); // adună-le
Fiecare metodă returnează un array, deci le înlănțui: filtrează → transformă → adună, citit de sus în jos ca o propoziție. Comparat cu bucla manuală echivalentă, e mai scurt, mai clar și mai greu de greșit.
gândirea funcțională
Diferența de mentalitate: bucla spune CUM (pas cu pas, cu indici și variabile temporare); map/filter/reduce spun CE vrei (transformă, păstrează, condensează). A doua e mai aproape de gândirea umană și mai puțin predispusă la erori. Stăpânirea acestor patru metode e un salt uriaș în JS.
modul 06 / obiecte & JSON
obiecte: proprietăți & metode
Un obiect grupează date înrudite sub chei cu nume. Dacă array-ul e o listă ordonată (accesată prin index), obiectul e o colecție etichetată (accesată prin nume). Modelezi „lucruri” din lumea reală: un utilizator, un produs, o setare.
crearea & accesul
const utilizator = {
nume: "Ana",
varsta: 30,
activ: true,
hobby: ["foto", "drumeții"]
};
utilizator.nume // "Ana" — notația cu punct (uzuală)
utilizator["varsta"] // 30 — notația cu paranteze (când cheia e dinamică)
- Perechi cheie: valoare, separate prin virgulă. Valorile pot fi orice: numere, string-uri, array-uri, alte obiecte, funcții.
- Notația cu punct (obj.cheie) e cea normală; cu paranteze (obj["cheie"]) când numele cheii e într-o variabilă sau conține spații.
modificare, adăugare, ștergere
utilizator.varsta = 31; // modifică
utilizator.email = "a@x.md"; // adaugă o cheie nouă
delete utilizator.activ; // șterge o cheie
"nume" in utilizator // true — cheia există?
metode & this
const cont = {
titular: "Ana",
sold: 100,
depune(suma) { // metodă = funcție într-un obiect
this.sold += suma; // „this” = obiectul curent
return this.sold;
}
};
cont.depune(50); // 150
- O metodă e o funcție care aparține obiectului — comportamentul „lucrului”.
- this se referă la obiectul pe care e apelată metoda (aici, cont). Permite metodei să acceseze celelalte proprietăți ale obiectului.
- Atenție: în arrow functions, this se comportă diferit — pentru metode de obiect folosește sintaxa clasică de mai sus.
destructuring & shorthand
const { nume, varsta } = utilizator; // extrage cheile în variabile
function salut({ nume }) { … } // destructuring în parametri
const nume = "Ion", varsta = 25;
const u = { nume, varsta }; // shorthand: { nume: nume, varsta: varsta }
array de obiecte — structura reală
Datele din lumea reală sunt aproape mereu array-uri de obiecte: o listă de utilizatori, produse, comenzi — fiecare un obiect. Combini tot ce ai învățat: utilizatori.filter(u => u.activ).map(u => u.nume). Aceasta e forma datelor pe care le vei procesa toată cariera.
modul 06 / obiecte & JSON
JSON: formatul datelor pe web
JSON (JavaScript Object Notation) e formatul standard de schimb de date pe web. Când o pagină cere date de la un server (modulul 9), aproape mereu le primește ca JSON. Seamănă izbitor cu obiectele JS — de aceea e atât de comod în JS.
cum arată
{
"nume": "Ana",
"varsta": 30,
"activ": true,
"hobby": ["foto", "drumeții"],
"adresa": { "oras": "Chișinău" }
}
reguli JSON (mai stricte decât obiectele JS)
- Cheile OBLIGATORIU în ghilimele duble (nu simple, nu fără).
- Valorile: string (ghilimele duble), number, boolean, null, array, obiect. Fără funcții, fără undefined, fără comentarii.
- Fără virgulă după ultimul element (trailing comma) — invalidează JSON-ul.
- E text — un string care descrie o structură, nu un obiect JS viu.
cele două conversii esențiale
// obiect JS → text JSON (pentru a trimite la server / a stoca):
const text = JSON.stringify(utilizator);
// '{"nume":"Ana","varsta":30,...}'
// text JSON → obiect JS (ce primești de la server):
const obiect = JSON.parse(text);
obiect.nume; // "Ana" — acum e obiect real, cu acces la proprietăți
- JSON.stringify(obiect) — serializează: obiect viu → string. Îl trimiți, îl salvezi (ex: în localStorage).
- JSON.parse(text) — deserializează: string → obiect viu. Ce faci cu răspunsul unui API.
- Capcană: JSON.parse pe un text invalid aruncă eroare — de aceea se pune adesea într-un try/catch (modulul 10).
localStorage — persistență simplă în browser
// salvezi (doar string-uri → deci stringify):
localStorage.setItem("user", JSON.stringify(utilizator));
// citești (→ deci parse):
const salvat = JSON.parse(localStorage.getItem("user"));
localStorage păstrează date în browser între vizite (setări, progres, coș). Ține doar text — de aici perechea JSON.stringify la scriere / JSON.parse la citire. Exact mecanismul pe care rulează progresul salvat al acestei platforme de cursuri.
de ce contează JSON
Practic orice comunicare între front-end și back-end trece prin JSON: cererile către API-uri, răspunsurile, configurările, bazele de date moderne. Perechea stringify/parse e printre cele mai folosite operații din dezvoltarea web. Stăpânește-o și ai deschis ușa spre aplicații reale, conectate.
modul 07 / DOM: manipularea paginii
ce este DOM-ul & selectarea elementelor
Aici JS-ul întâlnește pagina. DOM (Document Object Model) e reprezentarea HTML-ului ca un arbore de obiecte pe care JS îl poate citi și modifica. Când browserul parsează HTML-ul, construiește DOM-ul; JS-ul manipulează acel arbore, iar pagina se actualizează instant.
obiectul document
document e punctul de intrare — reprezintă întreaga pagină. Prin el găsești și modifici orice element.
selectarea elementelor
| Metodă | Ce returnează | Exemplu |
| querySelector(sel) | PRIMUL element care se potrivește (sau null) | document.querySelector(".btn") |
| querySelectorAll(sel) | TOATE elementele (o listă) | document.querySelectorAll("li") |
| getElementById(id) | Elementul cu acel id | document.getElementById("meniu") |
querySelector e vedeta: folosește exact selectorii CSS pe care îi știi deja — ".card", "#meniu", "nav a", "[data-id]". Un singur mod de gândire pentru CSS și JS.
const buton = document.querySelector(".btn-trimite");
const carduri = document.querySelectorAll(".card"); // listă
// parcurgi lista cu forEach:
carduri.forEach((card) => { … });
capcana null — de ce contează defer
- Dacă selectorul nu găsește nimic, querySelector returnează null. Apoi null.textContent → eroarea celebră „Cannot read properties of null”.
- Cauza #1: scriptul rulează înainte ca elementul să existe în pagină. Soluția: <script defer> (modulul 0) — rulează după ce DOM-ul e complet.
- Verifică selectorul: greșeli de tipar sau clasă inexistentă → null.
navigarea în arbore
De la un element ajungi la vecinii lui: .parentElement (părintele), .children (copiii), .closest(".card") (cel mai apropiat strămoș care se potrivește), .nextElementSibling. Utile mai ales în delegarea evenimentelor (modulul 8), când pornești de la elementul pe care s-a dat click.
modul 07 / DOM: manipularea paginii
modificarea conținutului, stilului & structurii
conținut: text & html
const titlu = document.querySelector("h1");
titlu.textContent = "Text nou"; // SIGUR — doar text
titlu.innerHTML = "<em>stil</em>"; // interpretează HTML — cu grijă!
- textContent — citește/scrie text pur. Sigur mereu: dacă pui text de la utilizator, e tratat ca text, nu ca cod.
- innerHTML — citește/scrie HTML (interpretat). Puternic, dar periculos cu date de la utilizator: cineva poate injecta cod (atac XSS). Regula: textContent pentru text, innerHTML doar pentru HTML pe care îl controlezi tu.
atribute & clase
img.setAttribute("src", "poza.jpg"); // setează atribut
link.getAttribute("href"); // citește
input.value = "text"; // valoarea unui câmp
el.classList.add("activ"); // adaugă o clasă
el.classList.remove("ascuns"); // scoate
el.classList.toggle("deschis"); // comută (adaugă/scoate)
classList e cea mai importantă tehnică de stilizare din JS: nu setezi stiluri direct din JS, ci comuți clase definite în CSS. Așa separi comportamentul (JS) de aspect (CSS) — meniul care se deschide, tab-ul activ, modalul vizibil, toate prin toggle de clasă.
stil direct (când e nevoie)
el.style.display = "none"; // ascunde
el.style.color = "#35E0E0"; // proprietăți CSS în camelCase (backgroundColor)
Folosește-l pentru valori dinamice/calculate (o poziție, o lățime din calcul); pentru stări repetabile, preferă classList + CSS.
crearea & inserarea de elemente
const li = document.createElement("li"); // creează
li.textContent = "Element nou";
li.classList.add("item");
lista.append(li); // adaugă la sfârșitul lui „lista”
el.remove(); // șterge un element din pagină
Fluxul complet: creezi (createElement) → configurezi (text, clase, atribute) → inserezi (append/prepend/before). Așa construiești liste, carduri, rânduri de tabel din date — de obicei combinat cu map peste un array de obiecte.
pattern-ul „date → pagină”
Cel mai frecvent tipar în web: ai un array de obiecte (produse, mesaje), și generezi HTML pentru fiecare. Fie cu createElement în buclă, fie construind un string cu map(...).join("") și punându-l în innerHTML (când datele sunt de încredere). Asta face, în esență, orice framework modern — automatizat.
modul 08 / evenimente
addEventListener & obiectul event
Evenimentele fac paginile interactive: reacția la click, tastare, trimiterea unui formular, scroll. Modelul e simplu: „când se întâmplă X pe elementul Y, rulează funcția Z”. Funcția Z se numește handler (sau listener).
addEventListener — modul corect
const buton = document.querySelector(".btn");
buton.addEventListener("click", () => {
console.log("Click!");
});
- Trei ingrediente: elementul, tipul evenimentului ("click"), funcția handler care rulează când se produce.
- Preferat față de onclick="" în HTML sau el.onclick =: poți adăuga mai mulți handleri pe același element, ții logica în JS, o poți și elimina (removeEventListener).
tipuri de evenimente frecvente
| Eveniment | Când se declanșează |
| click | Click (sau tap) pe element |
| input | La FIECARE modificare într-un câmp (pe măsură ce scrii) |
| change | Când câmpul își pierde focusul după modificare (sau la select/checkbox) |
| submit | La trimiterea unui formular |
| keydown / keyup | Apăsarea / eliberarea unei taste |
| mouseenter / mouseleave | Mouse-ul intră / iese de pe element |
| DOMContentLoaded | DOM-ul e complet parsat (pe document) |
obiectul event — informații despre ce s-a întâmplat
buton.addEventListener("click", (event) => {
console.log(event.target); // elementul pe care s-a produs
event.preventDefault(); // oprește acțiunea implicită
});
input.addEventListener("input", (e) => {
console.log(e.target.value); // ce a scris utilizatorul, în timp real
});
- Handler-ul primește automat un obiect event (uzual numit e) cu detalii: ce element (e.target), ce tastă, poziția mouse-ului etc.
- e.preventDefault() — oprește comportamentul implicit al browserului (ex: un formular să NU reîncarce pagina, un link să NU navigheze). Esențial la formulare.
principiu
Interactivitatea e, în esență, „ascultă evenimente, reacționează schimbând DOM-ul”. Combini tot cursul: un eveniment (click) declanșează un handler care citește date, decide (if), și modifică pagina (classList, textContent, createElement). Acesta e ciclul de viață al oricărei interacțiuni.
modul 08 / evenimente
propagare, delegare & formulare
bubbling — evenimentele „urcă” prin arbore
Când dai click pe un buton dintr-un card dintr-o listă, evenimentul se propagă în sus: butonul → cardul → lista → body → document. Fiecare strămoș „aude” click-ul. Se numește bubbling (ca bulele care urcă).
- De aceea un handler pus pe un container prinde și click-urile de pe copiii lui — o proprietate foarte utilă (vezi delegarea).
- event.stopPropagation() — oprește urcarea, când chiar ai nevoie (rar).
delegarea evenimentelor — pattern-ul cheie
Problemă: ai o listă cu 100 de elemente (sau elemente care apar dinamic). Pui 100 de handleri? Nu. Pui UN handler pe părinte și, când vine click-ul (prin bubbling), verifici pe ce copil s-a produs:
lista.addEventListener("click", (e) => {
const item = e.target.closest(".item");
if (!item) return; // click în afara unui item — ignoră
console.log("Click pe:", item.dataset.id);
});
- Un singur listener acoperă toți copiii, inclusiv cei adăugați ulterior (un handler direct nu s-ar lega de elemente care încă nu existau).
- e.target.closest(".item") urcă de la elementul exact al click-ului până la itemul-container.
- Delegarea e mai performantă (un handler vs sute) și mai robustă. Pattern esențial în interfețe dinamice.
evenimentele de formular
const form = document.querySelector("form");
form.addEventListener("submit", (e) => {
e.preventDefault(); // oprește reîncărcarea paginii
const nume = form.querySelector("#nume").value;
if (!nume.trim()) {
alert("Numele e obligatoriu");
return;
}
// procesează datele...
});
- submit pe <form> (nu click pe buton) — prinde și trimiterea cu Enter din tastatură.
- e.preventDefault() — fără el, browserul reîncarcă pagina (comportamentul implicit al formularului). Aproape mereu îl vrei la formulare gestionate cu JS.
- Citești valorile cu .value, validezi, apoi acționezi (trimiți la server, actualizezi pagina).
de reținut
Validarea nativă din HTML (required, type="email" — cursul de HTML) e prima linie și e gratis; validarea în JS o completează pentru reguli complexe și feedback personalizat. Iar validarea reală, de securitate, rămâne pe server — clientul poate fi ocolit oricând. Trei straturi, fiecare cu rolul lui.
modul 09 / cod asincron: promises, async/await & fetch
de ce asincron & promises
Unele operații durează: aducerea datelor de la un server, un timer, citirea unui fișier. Dacă JS ar aștepta „blocat” terminarea lor, pagina ar îngheța (butoanele n-ar răspunde). Soluția: codul asincron — pornești operația, continui cu altceva, și reacționezi când rezultatul e gata.
problema: JS e single-threaded
JS rulează pe un singur fir de execuție — face un lucru odată. Dacă un calcul lung îl blochează, toată pagina se blochează. De aceea operațiile lente (rețea, timere) sunt asincrone: nu opresc firul, ci anunță mai târziu că s-au terminat.
callbacks — prima soluție (și limita ei)
setTimeout(() => {
console.log("După 2 secunde");
}, 2000); // dai o funcție care rulează CÂND se termină timerul
Un callback = o funcție dată ca „sună-mă când termini”. Funcționează, dar când înlănțui multe operații dependente, ajungi la „callback hell” — funcții imbricate adânc, greu de citit și de gestionat erorile. De aici au apărut promises.
promises — o valoare care va veni
promisiune
.then((rezultat) => { … }) // când reușește
.catch((eroare) => { … }) // când eșuează
.finally(() => { … }); // oricum, la final
- Un Promise e un obiect care reprezintă un rezultat viitor: fie va reuși (resolve), fie va eșua (reject). E ca un bon de comandă — încă n-ai mâncarea, dar ai promisiunea ei.
- Trei stări: pending (în așteptare) → fulfilled (reușit) sau rejected (eșuat).
- .then() reacționează la succes, .catch() la eroare. Se pot înlănțui — mai plat decât callback-urile imbricate.
de ce contează
Aproape orice interacțiune reală cu lumea din afara paginii — aducerea de date, salvarea, autentificarea — e asincronă. Fără să stăpânești promises/async, rămâi la pagini statice. Cu ele, construiești aplicații care comunică. E granița dintre „pagină” și „aplicație web”.
modul 09 / cod asincron: promises, async/await & fetch
async/await & fetch
async/await — cod asincron care se citește ca sincron
async/await e zahăr sintactic peste promises — face codul asincron să arate liniar, natural, ușor de urmărit. E modul modern preferat.
async function iaDate() { // „async” marchează funcția
const raspuns = await fetch(url); // „await” așteaptă promisiunea
const date = await raspuns.json();
console.log(date);
}
- async înaintea unei funcții o marchează ca asincronă (returnează automat o promisiune).
- await „așteaptă” o promisiune să se rezolve și îți dă rezultatul direct — fără .then(). Codul de sub await rulează abia după ce promisiunea s-a terminat, dar firul nu se blochează între timp.
- await se poate folosi doar în funcții async.
gestionarea erorilor: try/catch
async function iaDate() {
try {
const raspuns = await fetch(url);
if (!raspuns.ok) throw new Error(`HTTP ${raspuns.status}`);
const date = await raspuns.json();
return date;
} catch (eroare) {
console.error("A eșuat:", eroare.message);
}
}
Cu async/await, erorile se prind cu try/catch normal (ca la cod sincron) — mult mai clar decât .catch() înlănțuit. Rețelele pică, serverele dau erori: codul asincron trebuie mereu să trateze eșecul.
fetch — aducerea datelor de pe web
const raspuns = await fetch("https://api.exemplu.md/produse");
const produse = await raspuns.json(); // parsează JSON-ul din răspuns
- fetch(url) e funcția standard pentru cereri HTTP din browser: aduce date de la un API, trimite formulare, salvează.
- Întoarce o promisiune cu un obiect Response; raspuns.json() (tot asincron) extrage și parsează corpul JSON.
- raspuns.ok / raspuns.status — verifici succesul (fetch NU aruncă eroare la 404/500; trebuie să verifici tu).
- Pentru a trimite date: fetch(url, { method: "POST", headers: {...}, body: JSON.stringify(date) }).
imaginea completă
Fluxul unei aplicații reale: un eveniment (click/submit) → o funcție async → fetch către un API → primești JSON → îl parse-uiești → generezi DOM din date → tratezi erorile cu try/catch. Toate modulele cursului converg aici. Ăsta e scheletul oricărei aplicații web moderne, indiferent de framework.
modul 10 / practici moderne, proiect & test final
javascript modern: module, erori & unelte
Ai fundamentele. Acest modul le leagă cu practicile care fac diferența dintre cod de începător și cod profesionist — apoi le pui pe toate la lucru într-un proiect.
module ES — organizarea codului în fișiere
// utils.js — EXPORTĂ funcționalități
export function formateazaPret(n) { return `${n.toFixed(2)} lei`; }
export const TVA = 0.2;
// app.js — IMPORTĂ ce are nevoie
import { formateazaPret, TVA } from "./utils.js";
- În loc de un fișier uriaș, împarți codul în module mici, fiecare cu rolul lui; export ce oferă, import ce folosești.
- În HTML: <script type="module" src="app.js">. Modulele sunt defer implicit și au scope propriu (nu poluează global).
- E baza organizării oricărui proiect modern și a ecosistemului npm (pachete instalabile).
tratarea erorilor
try {
const date = JSON.parse(textPoateInvalid);
} catch (eroare) {
console.error("JSON invalid:", eroare.message);
// tratează elegant — nu lăsa aplicația să crape
} finally {
// rulează oricum (curățenie)
}
throw new Error("Ceva nu e valid"); // arunci propria eroare
Codul robust anticipează eșecul: input invalid, rețea picată, date lipsă. try/catch prinde erorile ca aplicația să continue grațios în loc să se blocheze. Un profesionist se întreabă mereu „ce se poate strica aici?”.
debugging dincolo de console.log
- DevTools → Sources → breakpoints: oprești execuția pe o linie și inspectezi valorile variabilelor în acel moment, pas cu pas. Mai puternic decât console.log pentru bug-uri complexe.
- Citește mesajul de eroare complet: tipul (TypeError, ReferenceError), mesajul și stack trace-ul (lanțul de apeluri până la eroare, cu fișier și linie). Eroarea îți spune adesea exact ce și unde.
- debugger; — o linie care oprește execuția acolo (cu DevTools deschis), ca un breakpoint în cod.
strict mode & bune practici
- "use strict" (implicit în module) — prinde greșeli tăcute (variabile nedeclarate etc.).
- const by default, nume descriptive, funcții mici cu un singur rol, === mereu, tratarea erorilor — obiceiurile din tot cursul.
- Ecosistemul: npm (pachete), linters (ESLint — prinde greșeli), formattere (Prettier), bundlere (Vite) — le vei întâlni în proiecte reale. Fundamentele limbajului rămân aceleași dedesubt.
încotro de aici
Cu JS solid, urmează framework-urile (React, Vue) — care automatizează exact ce ai învățat manual: sincronizarea datelor cu DOM-ul, evenimente, componente. Ele au sens abia după ce înțelegi ce fac dedesubt. Fundamentul pe care l-ai construit e permanent; framework-urile vin și trec.
modul 10 / practici moderne, proiect & test final
proiect ghidat: mini-aplicație completă
Pui totul la lucru. Construiește o listă de sarcini (to-do) interactivă — mică, dar cu tot lanțul unei aplicații reale. Lucrează în editor, pas cu pas; implementarea e a ta, planul și criteriile sunt mai jos.
ce trebuie să facă
- Adaugă sarcini dintr-un input (cu validare: nu accepta gol).
- Afișează-le ca listă în pagină, generată din date.
- Marchează o sarcină ca terminată (click) și șterge-o (buton).
- Filtrează: toate / active / terminate.
- Salvează totul în localStorage — la reîncărcare, lista rămâne.
planul, pe module ale cursului
- Starea (modulele 1, 5, 6): un array de obiecte { id, text, gata } — sursa unică de adevăr. Tot ce se întâmplă modifică acest array, apoi redesenezi din el.
- Randarea (modul 7): o funcție reddeseneaza() care golește lista și o regenerează din array (map + createElement, sau innerHTML din date controlate). Aplicată filtrul curent cu filter.
- Evenimente (modul 8): submit pe formular (cu preventDefault + validare) pentru adăugare; delegare pe listă pentru click-urile de „terminat”/„șterge” (funcționează și pentru sarcinile adăugate dinamic).
- Funcții (modul 4): descompune în bucăți mici — adauga(), sterge(id), comuta(id), salveaza(), reddeseneaza(). Fiecare face un lucru.
- Persistență (modul 6): salveaza() = localStorage.setItem("todos", JSON.stringify(state)); la pornire, citești cu JSON.parse(localStorage.getItem("todos")) (cu fallback la array gol dacă e null).
- Robustețe (modul 10): try/catch la parse-ul din localStorage (dacă datele sunt corupte), validarea input-ului, stare goală tratată („Nicio sarcină încă”).
arhitectura mentală
stare (array) ──► reddeseneaza() ──► DOM
▲ │
└──── eveniment ◄── click/submit ────┘
(evenimentul modifică starea → salvează → redesenează)
Acest ciclu — stare → randare → eveniment → modifică starea → redesenează — e exact modelul pe care îl automatizează React și celelalte framework-uri. Dacă îl construiești manual o dată, înțelegi pentru totdeauna ce fac ele.
definiția lui „gata”
- Lista supraviețuiește reîncărcării (localStorage funcționează).
- Zero erori în consolă; input gol respins; delegarea prinde și sarcinile noi.
- const/let corect, funcții mici cu nume clare, === peste tot, un try/catch la datele din storage.
- Bonus: numărătoare de sarcini rămase, editare, sortare.
felicitări
Ai parcurs JavaScript de la console.log la o aplicație completă cu date, evenimente, asincronicitate și persistență. Ai acum al treilea strat al web-ului — comportamentul — și fundamentul pe care stau toate framework-urile moderne. Testul final urmează: 20 de întrebări din tot cursul. Prag: 70%.