🏗️ Objektorientētā programmēšana
ES6 klases sniedz skaidru un ērti lasāmu sintaksi objektorientētai programmēšanai JavaScript – mantošana, iekapsulācija un polimorfisms.
Klases un konstruktors
Teksts
// Klases definīcija
class Dzīvnieks {
// Lauki (ES2022 – klases lauki)
#nosaukums; // Privāts lauks (#)
#suga;
veids = "Dzīvnieks"; // Publisks lauks ar noklusējumu
// Konstruktors – tiek izsaukts ar "new"
constructor(nosaukums, suga) {
this.#nosaukums = nosaukums;
this.#suga = suga;
this.dzimšanas_gads = new Date().getFullYear();
}
// Metodes
runāt() {
return `${this.#nosaukums} saka: ${this.skaņa()}`;
}
skaņa() {
return "...";
}
// Getter
get nosaukums() {
return this.#nosaukums;
}
// Setter ar validāciju
set nosaukums(jaunais) {
if (typeof jaunais !== "string" || jaunais.trim().length < 1) {
throw new Error("Nosaukumam jābūt ne-tukšai virknei");
}
this.#nosaukums = jaunais.trim();
}
// Statiskā metode (uz klases, ne instances)
static radīt(nosaukums, suga) {
return new Dzīvnieks(nosaukums, suga);
}
toString() {
return `${this.#suga}: ${this.#nosaukums}`;
}
}
// Objekta izveide
const suns = new Dzīvnieks("Rex", "Suns");
console.log(suns.nosaukums); // "Rex" (getter)
suns.nosaukums = "Reks"; // Setter
console.log(suns.runāt()); // "Reks saka: ..."
console.log(`${suns}`); // "Suns: Reks" (toString)
// Statiskās metodes izsaukums uz klases
const kaķis = Dzīvnieks.radīt("Muris", "Kaķis");
Mantošana (extends)
Teksts
class Suns extends Dzīvnieks {
#šķirne;
constructor(nosaukums, šķirne) {
super(nosaukums, "Suns"); // Obligāts! Izsauc vecākklases konstruktoru
this.#šķirne = šķirne;
}
// Metodes pārrakstīšana (override)
skaņa() {
return "Hau!"; // Vecāku metode tagad atgriež "Hau!"
}
apraksts() {
return `${this.nosaukums} ir ${this.#šķirne} šķirnes suns`;
}
}
class Kaķis extends Dzīvnieks {
constructor(nosaukums) {
super(nosaukums, "Kaķis");
}
skaņa() { return "Miau!"; }
}
const reks = new Suns("Reks", "Dobermans");
const muris = new Kaķis("Muris");
console.log(reks.runāt()); // "Reks saka: Hau!"
console.log(muris.runāt()); // "Muris saka: Miau!"
console.log(reks.apraksts()); // "Reks ir Dobermans šķirnes suns"
console.log(reks instanceof Suns); // true
console.log(reks instanceof Dzīvnieks); // true (mantošana)
// ======================================
// Polimorfisms
// ======================================
const dzīvnieki = [
new Suns("Reks", "Dobermans"),
new Kaķis("Muris"),
new Dzīvnieks("Papagailis", "Putns"),
];
dzīvnieki.forEach(d => console.log(d.runāt()));
// "Reks saka: Hau!"
// "Muris saka: Miau!"
// "Papagailis saka: ..."
Privātie lauki un metodes
Teksts
class BankaKonts {
#atlikums = 0; // Privāts lauks
#darījumi = [];
constructor(īpašnieks, sākotnējā_nauda = 0) {
this.īpašnieks = īpašnieks;
if (sākotnējā_nauda > 0) this.#atlikums = sākotnējā_nauda;
}
iemaksāt(summa) {
this.#validētSummu(summa);
this.#atlikums += summa;
this.#reģistrētDarījumu("iemaksa", summa);
return this; // Method chaining
}
izmaksāt(summa) {
this.#validētSummu(summa);
if (summa > this.#atlikums) {
throw new Error("Nepietiek līdzekļu");
}
this.#atlikums -= summa;
this.#reģistrētDarījumu("izmaksa", -summa);
return this;
}
// Privātas metodes (arī ar #)
#validētSummu(summa) {
if (typeof summa !== "number" || summa <= 0) {
throw new Error("Summai jābūt pozitīvam skaitlim");
}
}
#reģistrētDarījumu(tips, summa) {
this.#darījumi.push({
tips,
summa,
laiks: new Date().toISOString(),
atlikums: this.#atlikums,
});
}
get atlikums() { return this.#atlikums; }
vēsture() {
return [...this.#darījumi]; // Kopija, nevis atsauce
}
}
const konts = new BankaKonts("Anna", 100);
konts.iemaksāt(50).iemaksāt(25); // Method chaining
konts.izmaksāt(30);
console.log(konts.atlikums); // 145
// konts.#atlikums // ❌ SyntaxError: privāts lauks
Statiskās metodes un lauki
Teksts
class Matemātika {
static PI = 3.14159265358979; // Statisks lauks
static aplis_laukums(r) {
return Matemātika.PI * r ** 2;
}
static aplis_perimetrs(r) {
return 2 * Matemātika.PI * r;
}
static #palīgs(x) { // Privāts statisks
return Math.round(x * 100) / 100;
}
static noapaļot(x) {
return Matemātika.#palīgs(x);
}
}
// Izsauc uz klases, ne instances!
console.log(Matemātika.PI); // 3.14159...
console.log(Matemātika.aplis_laukums(5)); // 78.54
// const m = new Matemātika();
// m.aplis_laukums // ← Kļūda, statiskās nav uz instancēm
// Singleton modelis
class Konfigurācija {
static #instance = null;
#iestatījumi = {};
static iegūt() {
if (!Konfigurācija.#instance) {
Konfigurācija.#instance = new Konfigurācija();
}
return Konfigurācija.#instance;
}
iestatīt(atslēga, vērtība) {
this.#iestatījumi[atslēga] = vērtība;
return this;
}
iegūtVērtību(atslēga) { return this.#iestatījumi[atslēga]; }
}
const konf1 = Konfigurācija.iegūt();
const konf2 = Konfigurācija.iegūt();
console.log(konf1 === konf2); // true – viena instance!
Mixins un kompozīcija
Teksts
// Mixin – funkcionalitātes pievienošana bez mantošanas
const Sērijveida = (SuperKlase) => class extends SuperKlase {
uz_json() {
return JSON.stringify(this);
}
static no_json(json) {
return Object.assign(new this(), JSON.parse(json));
}
};
const Validejams = (SuperKlase) => class extends SuperKlase {
validēt() {
const kļūdas = [];
for (const [atslēga, noteikums] of Object.entries(this.validācijas ?? {})) {
if (!noteikums(this[atslēga])) {
kļūdas.push(`${atslēga} nav derīgs`);
}
}
return kļūdas;
}
};
class Lietotājs extends Sērijveida(Validejams(class {})) {
validācijas = {
vārds: v => typeof v === "string" && v.length >= 2,
email: e => typeof e === "string" && e.includes("@"),
};
constructor(vārds, email) {
super();
this.vārds = vārds;
this.email = email;
}
}
const l = new Lietotājs("Anna", "anna@piemers.lv");
console.log(l.validēt()); // []
console.log(l.uz_json()); // {"vārds":"Anna","email":"anna@piemers.lv",...}