Învață programare
JavaScript pentru începători
Înveți bazele JavaScript cu exemple pe care le rulezi cu Node.js: valori, funcții, liste, obiecte, module și cod asincron.
JavaScript este limbajul care face paginile web interactive și, cu ajutorul Node.js, poate rula și direct pe calculatorul tău. Este un limbaj bun de început: ai rezultate rapid și îl folosești apoi la site-uri, aplicații și boți de Discord.
Ai nevoie de Node.js instalat, așa cum e descris în tutorialul despre mediul de lucru. Fiecare exemplu de aici se salvează într-un fișier cu extensia .js sau .mjs și se rulează cu node nume-fisier. Rezultatul exact apare sub fiecare exemplu.
Primul program: console.log
console.log afișează ceva în terminal. Textele se scriu între ghilimele simple sau duble. Numerele se scriu fără ghilimele. Observă diferența dintre a aduna două numere și a lipi două texte.
console.log('Salut, lume!');
console.log(2 + 3);
console.log('2' + '3');
Rezultat
Salut, lume!
5
23Un text se numește string. În ultima linie cele două texte au fost lipite, nu adunate matematic, de aceea rezultatul e 23. Ce urmează după // pe un rând este comentariu: calculatorul îl ignoră, iar tu îți lași notițe.
Valori, variabile și texte
Fiecare valoare are un tip. Cele mai des întâlnite: string (text), number (număr), boolean (adevărat sau fals), null (nimic, pus intenționat) și undefined (nimic, pentru că nu s-a dat nicio valoare). Cu typeof afli tipul unei valori.
const nume = 'Dana';
const varsta = 15;
const esteJucator = true;
const nimic = null;
let nedefinit;
console.log(typeof nume, typeof varsta, typeof esteJucator, typeof nimic, typeof nedefinit);
Rezultat
string number boolean object undefinedNu te mira că typeof null spune „object”. E o ciudățenie veche a limbajului, păstrată ca să nu se strice programele existente. Pentru null, verifici direct cu === null.
Cu let creezi o variabilă a cărei valoare poți s-o schimbi mai târziu. Cu const creezi una care nu se mai poate reatribui. Regula practică: folosește const, iar let doar când știi că valoarea se va schimba. Evită var, e varianta veche și are comportamente surprinzătoare.
let scor = 10;
scor = scor + 5;
const maxim = 100;
// maxim = 200; // ar da eroare: Assignment to constant variable.
console.log(scor, maxim);
Rezultat
15 100Pentru texte care conțin valori folosește template literals: text între ghilimele oblice (backtick), în care pui variabile între ${ și }. Sunt mult mai comode decât lipirea cu plus. Textele au și metode utile: length, toUpperCase, trim.
const jucator = 'Mihai';
const nivel = 7;
console.log(`Salut, ${jucator}! Nivel: ${nivel}`);
console.log(jucator.length);
console.log(jucator.toUpperCase());
console.log(' spații '.trim());
Rezultat
Salut, Mihai! Nivel: 7
5
MIHAI
spațiiLa numere ai operațiile obișnuite, plus restul împărțirii (%) și funcții din Math. Atenție la numerele cu zecimale: calculatorul le ține în binar, așa că apar mici imprecizii. Cu toFixed rotunjești la afișare.
console.log(7 + 2, 7 - 2, 7 * 2, 7 / 2);
console.log(7 % 2);
console.log(Math.floor(7 / 2));
console.log(0.1 + 0.2);
console.log((0.1 + 0.2).toFixed(2));
Rezultat
9 5 14 3.5
1
3
0.30000000000000004
0.30Liste (array) și obiecte
O listă, numită array, ține mai multe valori în ordine. Numărătoarea pozițiilor începe de la 0, deci primul element este lista[0]. Un obiect grupează date legate între ele, sub forma nume: valoare. Obiectele descriu lucruri precum un jucător, o armă sau un mesaj.
const arme = ['sabie', 'arc', 'topor'];
arme.push('scut');
console.log(arme.length, arme[0], arme[arme.length - 1]);
const jucator = { nume: 'Ioana', nivel: 4, arme: arme };
jucator.nivel = jucator.nivel + 1;
console.log(jucator.nume, jucator.nivel);
console.log(jucator.arme.join(', '));
Rezultat
4 sabie scut
Ioana 5
sabie, arc, topor, scutCondiții și bucle
if, else if și else aleg ce cod se execută. Pentru comparații folosește ===, care verifică și valoarea, și tipul. Operatorul == încearcă să convertească tipurile și produce surprize, așa că rămâi la ===.
function rang(nivel) {
if (nivel >= 50) {
return 'Veteran';
} else if (nivel >= 10) {
return 'Avansat';
}
return 'Începător';
}
console.log(rang(3), rang(12), rang(80));
console.log(5 === 5, 5 === '5', 5 == '5');
Rezultat
Începător Avansat Veteran
true false trueBucla for este bună când știi de câte ori repeți. while merge cât timp o condiție rămâne adevărată. for...of trece prin elementele unei liste, fără să te complici cu poziții.
for (let i = 1; i <= 3; i++) {
console.log('Pasul', i);
}
let numar = 3;
while (numar > 0) {
console.log('Numărătoare:', numar);
numar--;
}
for (const arma of ['sabie', 'arc']) {
console.log('Am', arma);
}
Rezultat
Pasul 1
Pasul 2
Pasul 3
Numărătoare: 3
Numărătoare: 2
Numărătoare: 1
Am sabie
Am arcDacă într-un while nu schimbi niciodată condiția, bucla nu se oprește. Dacă ți se întâmplă, apasă Ctrl+C în terminal ca să oprești programul.
Funcții și funcții săgeată
O funcție primește parametri și poate întoarce o valoare cu return. Există două scrieri: cu cuvântul function și cu săgeată (=>), mai scurtă. Pentru un parametru singur, parantezele pot lipsi. Dacă nu pui acolade, valoarea expresiei este întoarsă automat.
function aduna(a, b) {
return a + b;
}
const inmulteste = (a, b) => a * b;
const dubleaza = x => x * 2;
console.log(aduna(2, 3), inmulteste(4, 5), dubleaza(8));
Rezultat
5 20 16Aceste trei metode sunt folosite foarte des. map transformă fiecare element și întoarce o listă nouă. filter păstrează doar elementele care trec un test. reduce adună toată lista într-o singură valoare, pornind de la o valoare de start.
const xp = [30, 80, 150, 40];
const dublu = xp.map(x => x * 2);
const mari = xp.filter(x => x >= 50);
const total = xp.reduce((suma, x) => suma + x, 0);
console.log(dublu.join(', '));
console.log(mari.join(', '));
console.log(total);
Rezultat
60, 160, 300, 80
80, 150
300Proiect mic: nivelul din XP
Hai să punem totul laolaltă. Regula noastră inventată pentru exercițiu: fiecare 100 XP aduc un nivel, iar nivelul începe de la 1. Nu este regula vreunui joc anume, doar un exemplu pentru exersat.
function nivelDinXp(xp) {
return Math.floor(xp / 100) + 1;
}
function xpPanaLaUrmator(xp) {
return 100 - (xp % 100);
}
const jucatori = [
{ nume: 'Ana', xp: 50 },
{ nume: 'Bogdan', xp: 250 },
{ nume: 'Carmen', xp: 999 },
];
for (const j of jucatori) {
console.log(`${j.nume}: nivel ${nivelDinXp(j.xp)}, mai ai ${xpPanaLaUrmator(j.xp)} XP până la următorul`);
}
const total = jucatori.reduce((suma, j) => suma + j.xp, 0);
console.log(`XP total: ${total}`);
Rezultat
Ana: nivel 1, mai ai 50 XP până la următorul
Bogdan: nivel 3, mai ai 50 XP până la următorul
Carmen: nivel 10, mai ai 1 XP până la următorul
XP total: 1299Erori și module
Când ceva nu merge, Node.js îți spune ce și unde. Mesajul are, de obicei, numele erorii, o explicație și fișierul cu numărul rândului. Citește-l de sus în jos: primele rânduri sunt cele mai utile.
C:\exercitii\eroare.js:2
console.log(numele);
^
ReferenceError: numele is not defined
at Object.<anonymous> (C:\exercitii\eroare.js:2:13)
Aici ReferenceError înseamnă că ai folosit un nume care nu există: probabil o greșeală de scris sau o variabilă pe care ai uitat s-o creezi. Pentru erori pe care le poți prevedea, folosești try și catch: programul nu se oprește, ci tratează problema.
try {
JSON.parse('{ nu e json }');
} catch (eroare) {
console.log('Am prins o eroare:', eroare.name);
}
Rezultat
Am prins o eroare: SyntaxErrorPe măsură ce programul crește, îl împarți în fișiere. Un fișier oferă lucruri cu export, iar altul le folosește cu import. Pentru ca Node.js să trateze fișierul ca modul, dă-i extensia .mjs sau pune în package.json cheia type cu valoarea module. Exemplul are două fișiere, așa că îl vezi aici doar ca model.
export function patrat(x) {
return x * x;
}
import { patrat } from './matematica.mjs';
console.log(patrat(6));
Cod asincron: Promise și async/await
Unele lucruri durează: citirea unui fișier, un răspuns de la internet, un temporizator. În loc să blocheze tot programul, JavaScript pornește treaba și continuă. Rezultatul vine mai târziu, sub forma unui Promise (o promisiune). Cu async și await scrii codul ca și cum ar rula pe rând, deși nu blochează nimic.
function asteapta(ms) {
return new Promise(rezolva => setTimeout(rezolva, ms));
}
async function main() {
console.log('Încep');
await asteapta(20);
console.log('Au trecut 20 ms');
}
main();
console.log('Cod după main()');
Rezultat
Încep
Cod după main()
Au trecut 20 msObservă ordinea: după primul await, funcția main se oprește și programul merge mai departe, de aceea „Cod după main()” apare înaintea ultimei linii. Cu Promise.all aștepți mai multe lucruri deodată, iar rezultatele păstrează ordinea din listă, nu cea a terminării.
const pauza = (ms, valoare) => new Promise(rezolva => setTimeout(() => rezolva(valoare), ms));
const rezultate = await Promise.all([pauza(30, 'A'), pauza(10, 'B')]);
console.log(rezultate.join(' '));
Rezultat
A BAcelași limbaj rulează în două locuri. În browser primești obiecte pentru pagină, de exemplu document, cu care schimbi ce vede vizitatorul. În Node.js nu ai pagină, dar ai acces la fișiere, rețea și altele, adică exact ce îți trebuie pentru un server sau un bot. Limbajul e același, doar uneltele din jur diferă.
Unde se folosește în DominosLand
Botul de Discord DominosLand este scris în JavaScript, cu biblioteca discord.js (versiunea 14), și se află în serviciul bot-core. Un bot de Discord este, la bază, un program care stă conectat și reacționează la evenimente: un mesaj nou, o comandă, un membru care intră pe server. Pentru fiecare eveniment există o funcție care decide ce răspunde botul. Folosești aceleași ingrediente de mai sus: funcții, obiecte, condiții și async/await. Chei și token-uri secrete nu se scriu niciodată în cod și nu se pun în Git.