Məzmuna keçin
  • Kateqoriyalar
  • Ən yeni
  • Teqlər
  • Populyar
Yığmaq
Brend loqosu
codexC

codex

@codex
Haqqında
Yazı
70
Mövzu
59
Paylaşımlar
0
Qruplar
1
İzləyicilər
1
İzləyir
0

Yazı

Ən yeni

  • Java-da Inheritance və Composition: hansını, nə zaman istifadə etməliyik?
    codexC codex

    Java proqramlaşdırma dilində obyekt yönlü proqramlaşdırmanın (OOP) iki əsas anlayışı olan inheritance və composition proqramın strukturlaşdırılması və kodun təkrar istifadəsi baxımından çox vacib rol oynayır.

    Bu məqalədə hər iki anlayışı dərin təhlil edəcək, onların fərqlərini, üstünlüklərini və real nümunələr əsasında hansı vəziyyətdə hansının seçilməli olduğunu izah edəcəyik.


    🔷 Inheritance nədir?

    Inheritance - bir class-ın başqa bir class-ın xüsusiyyətlərini və metodlarını miras almasına imkan verən OOP prinsiplərindən biridir.

    Sadə nümunə:

    class Animal {
        void sound() {
            System.out.println("Heyvan səsi");
        }
    }
    
    class Dog extends Animal {
        void bark() {
            System.out.println("Hürmək");
        }
    }
    

    Burada Dog class-ı Animal class-ından miras alır və həm sound() metodunu istifadə edə bilir, həm də özünə məxsus bark() metoduna sahibdir.

    Inheritance-ın əsas xüsusiyyətləri:

    • extends açar sözü ilə yazılır.
    • Java-da çoxlu irsilik (multiple inheritance) yalnız interfeyslərlə mümkündür.
    • super açar sözü parent class-a müraciət etmək üçün istifadə olunur.

    ✅ Inheritance-ın üstünlükləri

    • Kod təkrarını azaldır. Eyni funksionallığı müxtəlif class-larda yenidən yazmağa ehtiyac yoxdur.
    • Quruluşlu ierarxiya yaradır. Class-lar arasında əlaqə vizual və konseptual cəhətdən aydın olur.
    • Yenidən istifadə imkanı. Mövcud kod bazasından yeni class-lar yaradıla bilər.

    ⚠️ Inheritance-ın çatışmazlıqları

    • Sıx bağlılıq (tight coupling). Əsas class-dakı dəyişikliklər törəmə class-lara təsir edə bilər.
    • Dizaynın çevikliyi azalır. Törəmə class-lar əsas class-ın strukturu ilə məhdudlaşır.
    • “Fragile base class” problemi. Əsas class-dakı dəyişikliklər bütün sistemə gözlənilməz təsir göstərə bilər.

    🧩 Composition nədir?

    Composition, bir class-ın başqa bir class-ı öz daxilində obyekt kimi saxlaması və onun metodlarından istifadə etməsi prinsipi üzərində qurulub.

    Yəni burada class-lar arasında “has-a” münasibəti olur.

    Sadə nümunə:

    class Engine {
        void start() {
            System.out.println("Mühərrik işə düşdü");
        }
    }
    
    class Car {
        private Engine engine = new Engine();
    
        void drive() {
            engine.start();
            System.out.println("Maşın hərəkət edir");
        }
    }
    

    Bu nümunədə Car class-ı Engine class-ını istifadə edir, lakin ondan irs almır.


    ✅ Composition-nun üstünlükləri

    • Sərbəstlik (loose coupling). Composition olunan class asanlıqla dəyişdirilə və əvəz edilə bilər.
    • Test etmək daha asandır. Mock obyektlər ilə testlər daha effektiv yazılır.
    • Dizayn daha çevik olur. Dinamik davranışlar asanlıqla idarə olunur.

    ⚠️ Composition-nun çatışmazlıqları

    • Dizaynın mürəkkəbləşməsi. Əgər çoxlu class-lar bir-birini compose edirsə, oxumaq və başa düşmək çətinləşə bilər.
    • Əlavə kod yazmaq tələb oluna bilər. Composition inheritance-ə nisbətən bir qədər daha çox konfiqurasiya tələb edir.

    🧠 Hansını nə zaman seçməli?

    Məsələ Inheritance Composition
    Münasibət “is-a” “has-a”
    Kod təkrarını azaltmaq ✔️ ✔️
    Çevik dizayn ❌ ✔️
    Test ediləbilərlik Orta Yüksək
    Valideyn dəyişiklikləri təsiri Yüksək Aşağı

    Sadə qayda:

    Əgər class-lar arasında “is-a” münasibəti varsa — Inheritance,
    “has-a” münasibəti varsa — Composition istifadə edin.


    🎯 Best Practice: “Prefer composition over inheritance”

    Məşhur dizayn prinsiplərindən biri də budur:

    “Composition-u Inheritance-dan üstün tutun”

    Çoxlu məşhur dizayn nümunələri (design patterns) də bu prinsipi əsas götürür:

    • Strategy pattern
    • Decorator pattern
    • Observer pattern və s.

    🔚 Nəticə

    Java proqramlarında Inheritance və Composition hər biri öz yerində çox faydalı vasitələrdir. Əsas məsələ — onları düzgün kontekstdə istifadə etməkdir. Inheritance daha sadə görünsə də, zamanla sistemin çevikliyinə zərər verə bilər. Ona görə də çox vaxt Composition-a üstünlük vermək daha sağlam yanaşmadır.

    Java composition inheritance oop is-a has-a

  • Java-da String və StringBuilder: fərqlər və istifadə qaydaları
    codexC codex

    Java proqramlaşdırma dilində mətnlə işləmək üçün ən çox istifadə olunan iki class var: String və StringBuilder. Bu məqalədə bu iki class-ın fərqlərini, üstünlüklərini və hansı hallarda istifadə olunmalı olduqlarını izah edəcəyik.


    1. String nədir?

    Java-da String — dəyişməz (immutable) bir obyekt növüdür. Yəni, bir dəfə yaradıldıqdan sonra onun məzmunu dəyişdirilə bilməz. Əgər dəyişiklik etsəniz, əslində yeni bir String obyekti yaranacaq.

    Nümunə:

    String ad = "Nilay";
    ad = ad + " Huseynova";
    System.out.println(ad); // Nəticə: Nilay Huseynova
    

    Yuxarıdakı nümunədə ad + " Huseynova" ifadəsi yeni bir String obyekt yaradır və köhnə obyekt dəyişmir. Bu səbəbdən çoxlu string birləşdirmələri performans baxımından zəif ola bilər.


    2. StringBuilder nədir?

    StringBuilder Java-da dəyişə bilən (mutable) string-lər yaratmaq üçün istifadə olunur. Bu class, xüsusilə çoxlu sayda string birləşdirmələri və dəyişikliklər aparıldıqda çox daha sürətli və effektiv işləyir.

    Nümunə:

    StringBuilder ad = new StringBuilder("Nilay");
    ad.append(" Huseynova");
    System.out.println(ad); // Nəticə: Nilay Huseynova
    

    Burada .append() metodu mövcud StringBuilder obyektinə əlavə edir və yeni obyekt yaratmır.


    3. String və StringBuilder arasındakı fərqlər

    Xüsusiyyət String StringBuilder
    Dəyişə bilmə Dəyişməz (immutable) Dəyişə bilən (mutable)
    Performans Aşağı (çoxlu birləşmələrdə) Yüksək
    Thread-safe Bəli (String təhlükəsizdir) Xeyr (lakin daha sürətlidir)
    İstifadə məqsədi Az dəyişiklik olan mətnlər Tez-tez dəyişən mətnlər üçün

    Qeyd: Əgər multithreading istifadə edirsinizsə və StringBuilder lazımdırsa, onun thread-safe versiyası olan StringBuffer istifadə olunmalıdır.


    4. Hansı zaman hansından istifadə etməli?

    Ssenari İstifadə
    Mətni bir neçə dəfə dəyişəcəksiniz StringBuilder
    Mətni nadir hallarda dəyişirsiniz və sadəcə oxuyursunuz String
    Multithreading mühitində təhlükəsizlik vacibdirsə StringBuffer
    == və .equals() ilə müqayisə edirsiniz String

    5. Əlavə faydalı StringBuilder metodları

    • .append(String s) – sonda string əlavə edir
    • .insert(int offset, String s) – müəyyən mövqeyə string əlavə edir
    • .replace(int start, int end, String s) – müəyyən hissəni əvəz edir
    • .delete(int start, int end) – hissəni silir
    • .reverse() – mətni tərsinə çevirir
    • .toString() – StringBuilder obyektini adi String-ə çevirir

    Nümunə:

    StringBuilder sb = new StringBuilder("Salam");
    sb.reverse();
    System.out.println(sb); // Nəticə: malaS
    

    6. String-lərin daxilindəki simvolları gözlənilməz davranışlar

    String a = "Java";
    String b = "Java";
    String c = new String("Java");
    
    System.out.println(a == b); // true (eyni obyektə işarə edir)
    System.out.println(a == c); // false (fərqli obyekt)
    System.out.println(a.equals(c)); // true (məzmun eynidir)
    

    Burada .equals() məzmun müqayisəsi aparır, == isə obyektin ünvanını yoxlayır.


    Nəticə

    Java-da String və StringBuilder hər biri fərqli hallarda istifadə edilməlidir:

    • String: dəyişməzdir, oxunaqlıdır, lakin performansı zəif ola bilər.
    • StringBuilder: dəyişkəndir, sürətlidir və string manipulyasiyası üçün idealdır.

    Sadə və az dəyişən mətni saxlamaq üçün String, lakin çoxlu dəyişiklik edilən mətnlər üçün StringBuilder seçmək daha düzgündür.

    Java string stringbuilder java

  • Shadow DOM və Virtual DOM nədir?
    codexC codex

    Modern veb inkişafında iki vacib anlayış tez-tez qarşımıza çıxır: Shadow DOM və Virtual DOM. Bunlar fərqli məqsədlərə xidmət etsələr də, hər ikisi istifadəçi interfeyslərinin effektiv və strukturlaşdırılmış şəkildə yaradılması üçün istifadə olunur. Bu məqalədə bu iki anlayışı sadə dillə izah edəcəyik və aralarındakı fərqləri göstərəcəyik.


    DOM nədir? (Qısa xatırlatma)

    DOM (Document Object Model) – HTML sənədinin JavaScript ilə idarə olunan obyekt formasında təqdim olunmasıdır. DOM vasitəsilə biz səhifədəki elementləri oxuya və dəyişə bilirik.

    Məsələn:

    document.querySelector("h1").textContent = "Salam, dünya!";
    

    Bu əmrlə h1 başlığının məzmununu dəyişirik.


    1. Shadow DOM nədir?

    Shadow DOM – DOM-un xüsusi bir hissəsidir ki, digər DOM elementlərindən izolyasiya olunmuşdur. Başqa sözlə, bu DOM strukturunda olan stil və ya funksiyalar əsas DOM-a təsir etməz və əsas DOM da ona təsir edə bilməz.

    Harada istifadə olunur?

    Shadow DOM əsasən Web Components texnologiyasının bir hissəsidir. Məsələn, siz öz my-button komponentinizi yaradırsınız və istəmirsiniz ki, başqa CSS qaydaları bu komponentin içini pozsun. O zaman Shadow DOM köməyə gəlir.

    Nümunə:

    <my-button></my-button>
    
    <script>
      class MyButton extends HTMLElement {
        constructor() {
          super();
          const shadow = this.attachShadow({ mode: "open" });
          shadow.innerHTML = `
            <style>
              button { background: red; color: white; }
            </style>
            <button>Click me</button>
          `;
        }
      }
    
      customElements.define("my-button", MyButton);
    </script>
    

    Üstünlükləri:

    • Stil və struktur tam izolyasiyalıdır.
    • Kapsullaşma (encapsulation) verir.
    • Yenidən istifadə edilə bilən komponentlər yaratmaq mümkün olur.

    2. Virtual DOM nədir?

    Virtual DOM – brauzerin real DOM-u ilə birbaşa işləmək əvəzinə, onun yaddaşda olan (virtual) surəti ilə işləmək metodudur. Bu texnika əsasən React, Vue kimi kitabxanalarda istifadə olunur.

    Niyə lazımdır?

    Real DOM ilə birbaşa işləmək çox yavaşdır, çünki hər dəyişiklik brauzerin render prosesini işə salır. Virtual DOM isə dəyişiklikləri əvvəlcə yaddaşda simulyasiya edir, sonra isə ən optimal formada real DOM-u yeniləyir.

    Necə işləyir?

    1. Komponentdə dəyişiklik olur.
    2. Virtual DOM-da yeni vəziyyət yaranır.
    3. Virtual DOM köhnə və yeni halı müqayisə edir (diffing).
    4. Yalnız dəyişən hissələr real DOM-a tətbiq olunur (reconciliation).

    Nümunə (React kontekstində):

    function App() {
      const [count, setCount] = useState(0);
    
      return (
        <div>
          <p>Sayaç: {count}</p>
          <button onClick={() => setCount(count + 1)}>Artır</button>
        </div>
      );
    }
    

    Bu halda React virtual DOM üzərində dəyişiklikləri hesablayır və yalnız p elementinin içini yeniləyir.


    Shadow DOM vs Virtual DOM

    Özəllik Shadow DOM Virtual DOM
    Texnologiya Web Components React, Vue və b. UI kitabxanaları
    Məqsəd Stil və DOM kapsullaşması Performansı artırmaq üçün DOM diffing
    Brauzer dəstəyi Native (birbaşa dəstəklənir) Kitabxana səviyyəsində tətbiq olunur
    Əlaqə Real DOM-un bir hissəsidir Real DOM-un surətidir (yaddaşda)
    Qapsama Bəli (izolyasiya olunmuşdur) Xeyr (ümumi DOM strukturunu təqlid edir)

    Hansı zaman hansından istifadə etməli?

    Ssenari Tövsiyə
    Öz komponentinizi hazırlayırsınız və stil qarışıqlığının qarşısını almaq istəyirsiniz Shadow DOM
    İnteraktiv və tez dəyişən istifadəçi interfeysi qurursunuz Virtual DOM (React, Vue və s.)
    Bütün brauzerlərdə işləməli universal komponentlər istəyirsiniz Shadow DOM-un dəstəyini yoxlayın və ya polyfill istifadə edin

    Nəticə

    Shadow DOM və Virtual DOM – hər ikisi veb inkişafında güclü texnologiyalardır. Shadow DOM daha çox komponent səviyyəsində təhlükəsizliyi və izolyasiyanı təmin edir. Virtual DOM isə performansı artıraraq böyük və interaktiv tətbiqlərin daha səmərəli işləməsinə şərait yaradır.

    Əgər Web Components ilə maraqlanırsınızsa – Shadow DOM öyrənməyə dəyər. Əgər React və ya Vue istifadə edirsinizsə – artıq Virtual DOM ilə işləyirsiniz!

    Front-end

  • package.json faylına ətraflı baxış
    codexC codex

    Node.js layihələri ilə işləyərkən ən önəmli fayllardan biri package.json faylıdır. Bu fayl layihə haqqında bütün əsas məlumatları, istifadə olunan asılılıqları (paketləri), skriptləri və digər konfiqurasiyaları ehtiva edir. Bir sözlə, layihənin idarəetmə mərkəzidir.

    1. Əsas sahələr

    name

    Layihənin adıdır. Kiçik hərflərlə yazılmalı və boşluq əvəzinə - (kəsik xətt) istifadə edilməlidir.

    "name": "my-first-app"
    

    version

    Layihənin versiyası. Bu versiya SemVer (Semantic Versioning) standartına əsaslanır: MAJOR.MINOR.PATCH (məs: 1.2.3)

    "version": "1.0.0"
    

    description

    Layihənin qısa izahı.

    "description": "Node.js ilə hazırlanmış API tətbiqi"
    

    main

    Node.js tərəfindən layihənin əsas giriş faylı kimi istifadə edilən yol.

    "main": "index.js"
    

    scripts

    Terminalda npm run əmri ilə işlədilə bilən skriptlər. Layihənin işə düşməsi, test olunması və s. bu sahədə qeyd olunur.

    "scripts": {
      "start": "node index.js",
      "dev": "nodemon index.js",
      "test": "jest"
    }
    

    keywords

    Layihənin axtarışda tapılması üçün açar sözlər siyahısıdır.

    "keywords": ["nodejs", "api", "express"]
    

    author və contributors

    Layihəni hazırlayan və ya ona töhfə verən şəxslərin siyahısı.

    "author": "Elvin Huseynov",
    "contributors": [
      {
        "name": "Aygün Məmmədova",
        "email": "aygun@example.com"
      }
    ]
    

    license

    Layihənin hüquqi istifadəsini müəyyən edən lisenziya tipi (məs: MIT, ISC, GPL-3.0 və s.)

    "license": "MIT"
    

    2. Asılılıqlar (Dependencies)

    Node.js layihələrində istifadə etdiyimiz kitabxanalar 3 əsas qrupa bölünür:

    dependencies

    Layihənin işləməsi üçün zəruri olan əsas paketlər.

    "dependencies": {
      "express": "^4.18.2",
      "mongoose": "~6.12.1"
    }
    

    devDependencies

    Yalnız inkişaf zamanı lazım olan paketlər – məsələn, test alətləri, linters, bundlers və s.

    "devDependencies": {
      "jest": "^29.7.0",
      "nodemon": "^3.0.1"
    }
    

    peerDependencies

    Bu sahədəki paketlər layihəyə daxil edilmir. Əsasən plugin və ya kitabxananın müəyyən versiya ilə işləməsini tələb edir.

    "peerDependencies": {
      "react": ">=17.0.0"
    }
    

    optionalDependencies

    Quraşdırılsa yaxşı olar, amma olmadan da işləyən paketlər. Quraşdırılarkən səhv olarsa, proses dayanmaz.

    "optionalDependencies": {
      "fsevents": "^2.3.2"
    }
    

    3. Versiya simvollarının mənası

    Versiya nömrələrinin əvvəlində olan bəzi simvollar var ki, onlar versiyanın necə seçildiyini göstərir:

    Simvol Mənası
    ^ Eyni əsas versiya daxilində olan ən son versiyanı qəbul et (default)
    ~ Eyni minor versiya daxilində ən son patch versiyanı qəbul et
    * Hər hansı versiyanı qəbul et
    >= Göstərilən versiyadan daha yuxarı olan versiyaları qəbul et
    <, <= Müvafiq olaraq daha kiçik və ya kiçik bərabər versiyaları göstər
    1.2.x 1.2.0 – 1.2.99 aralığında olan versiyalar

    Nümunə:

    "lodash": "^4.17.0"
    

    Bu halda, 4.17.0-dan başlayaraq 4.x.x aralığında olan ən son versiya quraşdırıla bilər, lakin 5.x.x yox.


    4. Digər faydalı sahələr

    engines

    Layihənin işləməsi üçün lazım olan Node.js və npm versiyasını göstərir.

    "engines": {
      "node": ">=16.0.0",
      "npm": ">=8.0.0"
    }
    

    type

    Modul sistemini təyin edir: "module" (ESM) və ya "commonjs".

    "type": "module"
    

    files

    Layihə npm publish ilə paylaşılarkən daxil ediləcək faylları göstərir.

    "files": ["dist/", "index.js"]
    

    private

    Layihənin səhvən npm publish ilə yayımlanmasının qarşısını alır.

    "private": true
    

    5. Tam package.json nümunəsi

    {
      "name": "codex-api",
      "version": "1.0.0",
      "description": "CodeX üçün REST API backend tətbiqi",
      "main": "server.js",
      "scripts": {
        "start": "node server.js",
        "dev": "nodemon server.js",
        "test": "jest"
      },
      "keywords": ["nodejs", "api", "backend"],
      "author": "Elvin Huseynov",
      "license": "MIT",
      "dependencies": {
        "express": "^4.18.2",
        "mongoose": "~6.12.1"
      },
      "devDependencies": {
        "jest": "^29.7.0",
        "nodemon": "^3.0.1"
      },
      "engines": {
        "node": ">=16.0.0"
      },
      "private": true
    }
    

    Nəticə

    package.json – yalnız texniki fayl deyil, sizin layihənizin struktur kitabçasıdır. Onu düzgün qurmaq, həm layihənin idarə olunmasını asanlaşdırır, həm də digərlərinin onu rahat şəkildə başa düşməsini təmin edir. Versiya simvollarının mənasını anlamaq isə asılılıqların stabil və təhlükəsiz olmasında mühüm rol oynayır.

    Qarışıq mövzular npm package nodejs

  • Singleton dizayn nümunəsi (Pattern)
    codexC codex

    Singleton pattern – proqramlaşdırmada geniş istifadə olunan bir dizayn nümunəsidir. Bu nümunənin əsas məqsədi — bir class-ın yalnız bir nüsxəsinin (instance) yaradılmasını təmin etmək və bu nüsxəyə qlobal səviyyədə çıxış imkanının olmasıdır.

    Bu pattern, proqram boyu paylaşılan resursların — məsələn, konfiqurasiya məlumatları, verilənlər bazası bağlantısı və s. — mərkəzləşdirilmiş şəkildə idarə olunması üçün çox yararlıdır.


    🔧 Məsələn: Singleton class-ın yaradılması

    class Singleton {
      constructor() {
        if (!Singleton.instance) {
          Singleton.instance = this;
        }
        return Singleton.instance;
      }
    
      someMethod() {
        console.log("Singleton method called");
      }
    }
    

    Qeyd:

    • Singleton.instance: Bu statik dəyişən artıq yaradılmış nüsxəni yadda saxlamaq üçün istifadə olunur.
    • constructor(): Classın yaradılmasında Singleton.instance yoxlanılır. Əgər belə bir instansiya yoxdursa, this (yeni instansiya) dəyişənə təyin olunur və o qaytarılır.
    • someMethod(): Class daxilində sadə bir metoddur, misal üçün konsola mesaj çıxarır.

    🧪 İstifadə

    const instance1 = new Singleton();
    const instance2 = new Singleton();
    
    console.log(instance1 === instance2); // true
    instance1.someMethod(); // "Singleton method called"
    
    • Hər iki dəyişən eyni instansiyaya işarə edir.
    • İstifadə zamanı artıq mövcud olan nüsxə qaytarılır və yenidən yaradılmır.

    ✅ Nəticə

    Singleton Pattern aşağıdakı hallarda faydalıdır:

    • Bir obyektin sistem boyu bir dəfə yaradılması lazımdırsa
    • Mərkəzləşdirilmiş idarəetmə (məsələn, Logger, Configuration, Database bağlantısı)
    • Resursların düzgün istifadəsi və davranışın sabitliyini təmin etmək
    Dizayn nümunələri design pattern singleton

  • Java-da İrsi̇li̇k (Inheritance)
    codexC codex

    💡 extends açar sözü

    Java-da bir class başqa bir class-dan miras alarkən extends açar sözündən istifadə edilir:

    class ChildClass extends ParentClass { ... }
    

    🔄 Metodun üstələnməsi (Overriding)

    Alt class, üst class-ın metodunu öz versiyası ilə dəyişə bilər:

    class Animal {
        void sound() {
            System.out.println("Some generic sound");
        }
    }
    
    class Cat extends Animal {
        @Override
        void sound() {
            System.out.println("Meow");
        }
    }
    

    🧱 İrsiliyin növləri Java-da

    1. Single Inheritance – yalnız bir class-dan miras alma
    2. Multilevel Inheritance – class-ın başqa bir class-dan miras alması və həmin class-ın da öz növbəsində miras alması
    3. Hierarchical Inheritance – bir neçə class-ın eyni class-dan miras alması

    Java multiple inheritance-i (çoxsaylı irsiliyi) class səviyyəsində dəstəkləmir, lakin interface-lər vasitəsilə bu mümkün olur.


    🔐 Access modifier-lərin təsiri

    Modifier Subclass daxilində görünür?
    public ✔️
    protected ✔️
    default ✔️ (eyni paketdədirsə)
    private ❌ Görünmür
    Java oop inheritance principles

  • Java-da Record və POJO nədir?
    codexC codex

    Java-da məlumatları modelləşdirmək üçün iki əsas yanaşma var: POJO və Record. Hər ikisi obyektin sahələrini (field) təyin edir, lakin istifadəsi və sintaksisi fərqlidir.


    📦 POJO nədir?

    POJO — “Plain Old Java Object” ifadəsinin qısaltmasıdır. Bu, heç bir xüsusi kitabxana və ya Java EE xüsusiyyətindən asılı olmayan, sadə Java obyektidir.

    Əsas xüsusiyyətlər:

    • Sahələr (fields)
    • Getter və setter metodları
    • Constructor (konstruktor)
    • toString(), equals(), hashCode() metodlarının override edilməsi (lazım olduqda)

    Misal:

    public class Person {
        private String name;
        private int age;
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() { return name; }
        public int getAge() { return age; }
    
        public void setName(String name) { this.name = name; }
        public void setAge(int age) { this.age = age; }
    
        @Override
        public String toString() {
            return name + " is " + age + " years old";
        }
    }
    

    🧾 Record nədir?

    Record — Java 14 ilə tanıdılmış və Java 16-da stabil olmuş yeni xüsusiyyətdir. O, POJO-ların qısa və daha səmərəli variantıdır. Record-lar immutable (dəyişməz) obyektlər yaratmaq üçün nəzərdə tutulub.

    Əsas xüsusiyyətlər:

    • Final sahələr (dəyişdirilə bilməz)
    • Avtomatik olaraq toString(), equals(), hashCode() metodları yaradılır
    • Getter-lər avtomatik olaraq ad ilə yaradılır (name(), age() və s.)
    • Setter yoxdur (dəyəri dəyişmək olmur)

    Misal:

    public record Person(String name, int age) { }
    

    Bu bir sətrə bərabər POJO-nu əvəz edə bilər və avtomatik olaraq aşağıdakıları təmin edir:

    • Constructor
    • name() və age() metodları
    • toString(), equals(), hashCode() metodları

    🆚 POJO vs Record

    Xüsusiyyət POJO Record
    Mutability Dəyişilə bilən (mutable) Dəyişməz (immutable)
    Kod miqdarı Uzun Qısa və yığcam
    Getter və Setter Manual yazılır Getter-lər avtomatik, setter yoxdur
    Java versiyası Java 1.0 və sonrası Java 14+ (eksperimental), 16+ (stabil)
    Tətbiq sahəsi Mürəkkəb modellər, ORM, vs. Sadə məlumat daşıyıcıları (DTO)

    📌 Nəticə

    • POJO daha çox konfiqurasiya və çeviklik tələb edən hallarda istifadə olunur.
    • Record isə daha çox dəyişməz və sadə məlumat modelləri üçün idealdır.

    Əgər məqsədiniz sadəcə məlumatı daşımaqdır və onu dəyişmək ehtiyacınız yoxdursa, Record istifadəsi tövsiyə olunur. Əlavə olaraq Record Java proqramlarında DTO (Data Transfer Object) kimi geniş istifadə edilir, xüsusilə REST API-lərdə request və response modellərində çox faydalıdır.

    Java pojo record immutable object

  • Prototype nümunəsi (Prototype Pattern)
    codexC codex

    Prototype Pattern obyektlərin mövcud bir nümunədən (şablondan) klonlanaraq yaradılmasına imkan verir. Bu nümunə, eyni tipli obyektlərin ortaq metod və xüsusiyyətlər paylaşmasını təmin edir. Bu da yaddaşdan daha səmərəli istifadə və vahid davranış təmin edir.


    🔧 Məsələyə JavaScript nümunəsi ilə baxaq:

    // Constructor funksiyası yaradılır
    function Person(name, age) {
      this.name = name;
      this.age = age;
    }
    
    // Prototipə metod əlavə olunur
    Person.prototype.greet = function () {
      console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
    };
    
    // İki obyekt nümunəsi yaradılır
    const person1 = new Person("Alice", 30);
    const person2 = new Person("Bob", 25);
    

    🧠 Bu kod nə edir?

    1. Constructor Function – Qurucu Funksiya

    Person adlı funksiya yaradılır və bu funksiya yeni obyektlərə name və age təyin edir.

    2. Prototype vasitəsilə metodun paylaşılması

    greet adlı metod Person.prototype-ə əlavə olunur. Bu, o deməkdir ki, bütün Person obyektləri bu metodu paylaşır – hər biri üçün ayrı nüsxə saxlanmır. Bu da yaddaşa qənaət deməkdir.

    3. Yeni obyektlərin yaradılması

    new Person(...) ilə person1 və person2 kimi fərqli dəyərlərə malik obyektlər yaradılır.


    💡 İstifadə

    person1.greet(); // Çıxış: Hello, my name is Alice and I am 30 years old.
    person2.greet(); // Çıxış: Hello, my name is Bob and I am 25 years old.
    

    Burada hər bir obyekt greet() metodunu çağırır, lakin metod prototipdən gəlir və obyektin öz name və age dəyərləri ilə işləyir.


    📝 Yekun

    Prototype Pattern əsasən aşağıdakı hallarda istifadə olunur:

    • Obyektlərin yaradılması resurs baxımından baha başa gəlirsə və tez-tez təkrar yaradılmalıdırsa
    • Eyni davranış və funksionallığı çox sayda obyekt paylaşmalıdırsa
    • Kodda yaddaşa qənaət və vahid metod strukturu təmin olunmalıdırsa

    Bu nümunə JavaScript-in prototip əsaslı obyekt sistemini başa düşmək üçün də ideal bir başlanğıcdır.

    Dizayn nümunələri prototype design pattern creational

  • Builder dizayn nümunəsi (Builder Pattern)
    codexC codex

    Builder dizayn nümunəsi, mürəkkəb obyektlərin yaradılmasını onların təqdimatından ayırmağa imkan verir. Bu, zəncirvari çağırma prosesindən istifadə edərək müxtəlif təqdimatlara malik obyektlər yaratmağa şərait yaradır.


    🏗️ Misal üzərindən izah

    Car class-ı

    class Car {
      constructor(builder) {
        this.make = builder.make;
        this.model = builder.model;
        this.year = builder.year;
        this.color = builder.color;
        this.engine = builder.engine;
      }
    
      toString() {
        return `${this.year} ${this.make} ${this.model} in ${this.color} with a ${this.engine} engine`;
      }
    }
    

    Burada Car class-ı avtomobilin xüsusiyyətlərini saxlayır: marka, model, il, rəng və mühərrik. Bu class CarBuilder vasitəsilə yaradılır.


    CarBuilder class-ı

    class CarBuilder {
      constructor(make, model) {
        this.make = make;
        this.model = model;
      }
    
      setYear(year) {
        this.year = year;
        return this;
      }
    
      setColor(color) {
        this.color = color;
        return this;
      }
    
      setEngine(engine) {
        this.engine = engine;
        return this;
      }
    
      build() {
        return new Car(this);
      }
    }
    

    CarBuilder addım-addım obyektin qurulmasına imkan verir. Hər metod müəyyən xüsusiyyəti təyin edir və this qaytardığı üçün zəncirvari çağırma (method chaining) mümkündür.


    🧠 Kodun izahı

    1. Zəncirvari interfeys (Fluent interface): CarBuilder metodlarının hər biri this qaytararaq, ardıcıl çağırmalara imkan verir.
    2. Ayrılmış məsuliyyət (Separation of concerns): Avtomobilin necə qurulacağı CarBuilder-də, nəyi təmsil etdiyi isə Car class-ında müəyyən edilir.
    3. Dəyişməzlik (Immutability): Car obyekti qurulduqdan sonra onun sahələri dəyişməz qalır.

    🛠️ İstifadə nümunəsi

    const car = new CarBuilder("Toyota", "Camry")
      .setYear(2021)
      .setColor("Red")
      .setEngine("V6")
      .build();
    
    console.log(car.toString());
    // Nəticə: 2021 Toyota Camry in Red with a V6 engine
    
    Dizayn nümunələri builder design pattern creational

  • React.memo: nə zaman kömək edir, nə zaman zərər verir
    codexC codex

    React tətbiqlərində performans optimizasiyası üçün tez-tez istifadə olunan React.memo komponenti, düzgün istifadə edildikdə faydalı ola bilər. Lakin, bəzi hallarda bu alət gözlənilməz nəticələrə səbəb ola bilər. Bu məqalədə React.memo-nun necə işlədiyini, hansı hallarda effektiv olduğunu və hansı hallarda problem yaratdığını araşdıracağıq.


    Memoizasiyanın vəd etdikləri

    React tətbiqləri yavaşladıqda, proqramçılar tez-tez React.memo, useMemo və useCallback kimi memoizasiya alətlərinə müraciət edirlər. Bu alətlər, lazımsız yenidən renderlərin qarşısını almaqla performansı artırmaq məqsədi daşıyır. Lakin, bu alətlərin istifadəsi düşündüyümüzdən daha mürəkkəb ola bilər.


    JavaScript-də referans müqayisələri

    JavaScript-də primitiv dəyərlər (məsələn, ədədlər, sətirlər) dəyərə görə müqayisə olunur, obyektlər isə referansa görə:

    // Primitiv dəyərlər dəyərə görə müqayisə olunur
    const a = 1;
    const b = 1;
    console.log(a === b); // true
    
    // Obyektlər referansa görə müqayisə olunur
    const objA = { id: 1 };
    const objB = { id: 1 };
    console.log(objA === objB); // false, fərqli referanslar
    

    Bu, React-də problem yarada bilər, çünki komponentlərə ötürülən obyekt və funksiyalar hər renderdə yeni referanslara sahib olur və bu, lazımsız yenidən renderlərə səbəb ola bilər.


    useMemo və useCallback necə işləyir

    React, referansların sabit qalmasını təmin etmək üçün useMemo və useCallback hook-larını təqdim edir.

    • useMemo: Məhsuldar (expensive) hesablamaların nəticəsini yadda saxlayır və yalnız asılılıqlar dəyişdikdə yenidən hesablayır.
      const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
    
    • useCallback: Funksiyaların referansını yadda saxlayır və yalnız asılılıqlar dəyişdikdə yeni funksiyanı yaradır.
      const memoizedCallback = useCallback(() => {
        doSomething(a, b);
      }, [a, b]);
    

    React.memo necə işləyir

    React.memo yüksək səviyyəli bir komponentdir (HOC) və komponentin props-larını səthi (shallow) şəkildə müqayisə edərək, dəyişiklik olmadıqda yenidən renderin qarşısını alır:

    const MyComponent = React.memo(function MyComponent(props) {
      // komponentin implementasiyası
    });
    

    Lakin, əgər komponentə ötürülən props-lar hər renderdə yeni referanslara sahib olursa (məsələn, obyektlər və ya funksiyalar), React.memo bu dəyişiklikləri görəcək və komponenti yenidən render edəcək.


    React.memo istifadəsində ümumi problemlər

    1. Props-ların spreading-i

    Props-ları yaymaq (spread) React.memo-nun effektivliyini poza bilər:

    const Child = React.memo(({ data }) => {
      // komponentin implementasiyası
    });
    
    const Parent = (props) => {
      return <Child {...props} />;
    };
    

    Bu halda, Child komponentinə ötürülən props-ların referansları dəyişə bilər və bu, yenidən renderə səbəb olar.

    2. children prop-u problemi

    JSX-də children də bir prop-dur və hər renderdə yeni referansa sahib olur:

    const MemoComponent = React.memo(({ children }) => {
      // implementasiya
    });
    
    const Parent = () => {
      return (
        <MemoComponent>
          <div>Some content</div>
        </MemoComponent>
      );
    };
    

    Bu halda, MemoComponent hər dəfə yenidən render olunacaq.

    3. İç-içə memo komponentləri problemi

    Bir-birinin içində yerləşən memo komponentlər də problem yarada bilər:

    const InnerChild = React.memo(() => <div>Inner</div>);
    const OuterChild = React.memo(({ children }) => <div>{children}</div>);
    
    const Parent = () => {
      return (
        <OuterChild>
          <InnerChild />
        </OuterChild>
      );
    };
    

    Bu halda, OuterChild hər dəfə yenidən render olunacaq, çünki InnerChild hər dəfə yeni bir JSX elementi yaradır.

    Həll yolu: useMemo istifadə edərək InnerChild-ı yadda saxlamaq:

    const Parent = () => {
      const innerChild = useMemo(() => <InnerChild />, []);
    
      return <OuterChild>{innerChild}</OuterChild>;
    };
    

    Memoizasiyanı nə zaman istifadə etməli

    React.memo istifadə edin əgər:

    1. Komponentiniz saf funksional komponentdirsə və eyni props-larla eyni nəticəni qaytarırsa.
    2. Komponent tez-tez eyni props-larla render olunursa.
    3. Render prosesi məhsuldardırsa (expensive).
    4. Profilinq vasitəsilə performans problemi olduğunu təsdiqləmisinizsə.

    useMemo istifadə edin əgər:

    1. Məhsuldar bir hesablamanı hər renderdə təkrar etmək istəmirsinizsə.
    2. Memoizə edilmiş komponentə ötürülən obyekt və ya array-ın sabit referansını saxlamaq istəyirsinizsə.
    3. Hesablamanın həqiqətən məhsuldar olduğunu ölçüb təsdiqləmisinizsə.

    useCallback istifadə edin əgər:

    1. Optimallaşdırılmış child komponentlərinə referans bərabərliyinə əsaslanan callback-lar ötürürsünüzsə.
    2. Callback useEffect hook-unda asılılıq kimi istifadə olunursa.
    3. Memoizə edilmiş komponentlərdə sabit funksional referans saxlamaq istəyirsinizsə.

    Alternativ: Komponent kompozisiyası

    Memoizasiyadan əvvəl, komponent strukturunuzu kompozisiya vasitəsilə yaxşılaşdırmağı düşünün. Komponent kompozisiyası tez-tez performans problemlərini daha zərif şəkildə həll edir.

    Məsələn, məhsuldar bir komponenti memoizə etmək əvəzinə, vəziyyəti daha spesifik bir konteynerə keçirin.

    React memo usememo usecallback memoizasiya

  • JavaScript Regular ifadələr (Regex) bələdçisi
    codexC codex

    Regular ifadələr (Regular Expressions və ya qısaca Regex) JavaScript-də mətnlə işləmək üçün çox güclü bir alətdir. Onlar mətn axtarışı, dəyişdirmə, doğrulama və parçalama işlərini sadələşdirir. Bu məqalədə regulər ifadələrin əsas prinsiplərindən başlayaraq, onların real layihələrdə necə istifadə olunduğuna qədər geniş şəkildə izah veriləcək.


    🔤 Regular ifadə nədir?

    Regular ifadə — müəyyən bir mətn nümunəsini tapmaq və onun üzərində əməliyyat aparmaq üçün istifadə olunan xüsusi simvollardan ibarət sintaksisdir. Məsələn, bir sənəddə bütün e-poçt ünvanlarını tapmaq üçün istifadə oluna bilər.


    🧱 Regulər ifadələrin yaradılması

    JavaScript-də regex yaratmağın iki üsulu var:

    1. Regex literal:

    const pattern = /abc/;
    

    2. RegExp konstruktoru:

    const pattern = new RegExp("abc");
    

    İkinci üsul əsasən dinamik ifadələr yaratmaq üçün istifadə olunur.


    🧪 Əsas Regex simvolları və strukturu

    Simvol Təsvir
    . Hər hansı bir simvol (yeni sətrdən başqa)
    \d Rəqəm (0-9)
    \w Hərf, rəqəm və alt xətt
    \s Boşluq simvolu
    ^ Sətirin başlanğıcı
    $ Sətirin sonu
    * 0 və ya daha çox
    + 1 və ya daha çox
    ? 0 və ya 1 dəfə
    {n} Dəqiq sayda təkrarlanma
    [abc] Sadalanan simvollardan biri
    [^abc] Sadalanan simvollardan başqa biri
    (a | b) “a” və ya “b”

    🚩 Bayraqlar (Flags)

    Regex-lər əlavə parametrlərlə işləyə bilər:

    • g (global): Bütün uyğunluqları tapmaq üçün
    • i (ignoreCase): Böyük-kiçik hərf fərqini nəzərə almamaq üçün
    • m (multiline): Çoxsətirli rejim üçün
    • u (unicode): Unicode dəstəyi üçün

    🔍 Praktik nümunələr

    1. E-poçt doğrulaması:

    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    

    2. Telefon nömrəsi doğrulaması:

    const phoneRegex = /^\+994\d{9}$/;
    

    3. Mətn daxilində söz axtarmaq:

    const sentence = "Salam dünya";
    const result = /dünya/.test(sentence); // true
    

    💡 Regex ilə əvəzləmə

    String.prototype.replace() metodu regex ilə birlikdə güclü bir vasitəyə çevrilir:

    const text = "Salam, 123";
    const cleaned = text.replace(/\d/g, ""); // "Salam, "
    

    🔎 Regex və match(), test(), exec()

    • test() — uyğunluq olub olmadığını true/false qaytarır
    • match() — uyğunluqları massiv şəklində qaytarır
    • exec() — bir uyğunluğu obyekt kimi qaytarır
    let pattern = /Hello/;
    let input = "Hello, World!";
    let result = input.match(pattern);
    console.log(result);
    

    6d02769f-a459-415f-9f91-30d4a109a141-image.png

    const pattern = /\(\d{3}\) \d{3}-\d{4}/g;
    const string = "My phone numbers are (123) 456-7890 and (555) 555-1212.";
    
    let matches;
    while (matches = pattern.exec(string)) {
      console.log(matches);
    }
    

    b1bbaf1b-2039-42e2-b1a8-db10504a9196-image.png


    💼 Real layihələrdə regex istifadəsi

    • Form doğrulama: istifadəçi məlumatlarının düzgünlüyünü yoxlamaq
    • Data parsing: log fayllarından və ya mətndən məlumat çıxarma
    • Text search: mətnlərdə açar sözlərin tapılması
    • Syntax highlighting: kod redaktorlarında sözlərin rənglənməsi
    • Router Matching: URL marşrutlarının uyğunlaşdırılması (məsələn, /product/:id kimi)

    🚨 Bəzi tələ və çətinliklər

    • Regex-lər oxunması və yazılması çətin ola bilər, buna görə sadə ifadələrlə başlamaq məsləhətdir.
    • Performans məsələlərinə diqqət yetirin: çox kompleks ifadələr performansı azalda bilər.
    • Regex ilə hər problemi həll etməyə çalışmayın – bəzən sadə string metodları kifayət edir.

    ✅ Nəticə

    JavaScript-də regulər ifadələr, effektiv və çevik mətn işləmə vasitəsidir. Onları mənimsəmək, xüsusilə form doğrulama və məlumat emalı ilə məşğul olan proqramçılar üçün vacibdir. Sadə regex-lərlə başlayın və tədricən daha mürəkkəb nümunələrə keçin.

    JavaScript regex

  • JavaScript-də Prototype Chain (Prototip Zənciri)
    codexC codex

    Bu 10 sual vasitəsilə JavaScript-in prototype zənciri, __proto__, prototype, Object.create(), constructor funksiyalar və new-in daxili iş prinsipi ətraflı şəkildə izah olundu. Bu biliklər JavaScript-i daha dərin anlamaq və daha güclü tətbiqlər yazmaq üçün vacibdir.

    ✅ 1. Prototype zənciri nədir?

    Cavab: Prototype zənciri — JavaScript obyektlərinin digər obyektlərdən metod və propertiləri irsi olaraq almasına imkan verən mexanizmdir. JavaScript-də hər obyektin __proto__ adlı gizli bir xassəsi olur və bu xassə həmin obyektin hansı digər obyektdən miras aldığını göstərir. Axtarılan property obyektin özündə yoxdursa, JavaScript həmin property-ni zəncir üzrə yuxarıdakı prototiplərdə axtarır.


    ✅ 2. __proto__ və prototype arasında fərq nədir?

    Cavab:

    • __proto__ — istənilən obyektin daxili [[Prototype]] (gizli irsi əlaqəsi) istinadıdır.
    • prototype — yalnız constructor funksiyalara (məsələn, function A() {}) aid olan xassədir və new ilə yaradılmış obyektlərin __proto__su bu prototype-ə istinad edir.

    Sadə desək:

    const obj = new Constructor();
    obj.__proto__ === Constructor.prototype // true
    


    ✅ 3. Aşağıdakı kodun nəticəsi nə olacaq? İzah edin.

    function Person(name) {
      this.name = name;
    }
    Person.prototype.greet = function() {
      return "Hello, " + this.name;
    };
    
    const p1 = new Person("John");
    
    console.log(p1.greet()); // ?
    console.log(p1.__proto__ === Person.prototype); // ?
    

    Cavab:

    • p1.greet() → "Hello, John" — çünki greet metodu Person.prototype-dədir.
    • p1.__proto__ === Person.prototype → true — çünki new ilə yaradılmış obyektlərin __proto__su həmin constructor-un prototype-inə bərabər olur.


    ✅ 4. JavaScript-də __proto__ necə işləyir?

    Cavab: JavaScript obyekt üzərində bir property tapmayanda, avtomatik olaraq __proto__ vasitəsilə onun prototipinə baxır. Bu proses zəncirvari davam edir — yuxarı prototiplərə baxılır — ta ki null-a çatana qədər (Object.prototype.__proto__ === null).


    ✅ 5. Bu kod niyə işləmir?

    const obj = {
      name: "Elvin",
      sayHi: function() {
        return "Hi " + this.name;
      }
    };
    
    obj.prototype = function sayHi() {
      return "Hello " + this.name;
    };
    obj.sayHi();
    

    Cavab: Burada səhv odur ki, obj adi obyekt olduğu üçün onun prototype property-si işləmir. prototype yalnız constructor funksiyalar üçün işləyir. Bu şəkildə olmalı idi:

    function Person(name) {
      this.name = name;
    }
    Person.prototype.sayHi = function() {
      return "Hello " + this.name;
    };
    


    ✅ 6. Aşağıdakı kodun nəticəsi nə olacaq? Niyə?

    const animal = {
      eats: true
    };
    
    const rabbit = Object.create(animal);
    rabbit.jumps = true;
    
    console.log(rabbit.eats);  // ?
    console.log(rabbit.jumps); // ?
    console.log(animal.jumps); // ?
    

    Cavab:

    • rabbit.eats → true — irsi olaraq animal-dan gəlir
    • rabbit.jumps → true — öz property-dir
    • animal.jumps → undefined — çünki jumps yalnız rabbit-ə aiddir


    ✅ 7. Object.create() nədir və onu new əvəzinə nə vaxt istifadə edərik?


    Cavab:

    • Object.create(proto) — yeni bir obyekt yaradır və onun __proto__-sunu verdiyimiz proto obyektinə bağlayır.
    • new ilə müqayisədə Object.create() bizə birbaşa prototipi təyin etməyə imkan verir. Əgər constructor funksiyadan istifadə etmiriksə, sadə obyekt irsiliyi üçün Object.create() daha uyğundur.


    ✅ 8. Bu kodun nəticəsi nədir? Niyə?

    function A() {}
    A.prototype = {
      sayHello: function() {
        return 'Hello from A';
      }
    };
    
    const obj = new A();
    
    A.prototype = {
      sayHello: function() {
        return 'Hello from modified A';
      }
    };
    
    console.log(obj.sayHello());
    

    Cavab: obj.sayHello() → "Hello from A"
    Çünki obj yaradıldıqdan sonra A.prototype dəyişdirilsə də, obj artıq köhnə prototipi saxlayır. Yeni prototype ancaq sonrakı instansiyalara təsir edərdi.


    ✅ 9. new əməliyyatını özümüz necə implement edə bilərik?

    Cavab:

    function myNew(Constructor, ...args) {
      const obj = {};
      Object.setPrototypeOf(obj, Constructor.prototype);
      const result = Constructor.apply(obj, args);
      return typeof result === 'object' && result !== null ? result : obj;
    }
    

    Bu funksiyamız:

    1. Boş obyekt yaradır
    2. Onun __proto__sunu constructor-un prototype-inə bağlayır
    3. Constructor-u həmin obyektə this kimi tətbiq edir
    4. Əgər constructor obyekt qaytarmırsa, yeni obyekt qaytarılır


    ✅ 10. Bu kodun nəticəsi nə olacaq? Niyə dəyişir?

    const grandParent = {
      greet: function() {
        return "Hello from GrandParent";
      }
    };
    
    const parent = Object.create(grandParent);
    const child = Object.create(parent);
    
    parent.greet = function() {
      return "Hello from Parent";
    };
    
    console.log(child.greet());
    delete parent.greet;
    console.log(child.greet());
    

    Cavab:

    • Birinci console.log → "Hello from Parent" — çünki child.greet() zəncirdə parent-da tapılır
    • İkinci console.log → "Hello from GrandParent" — çünki parent.greet silinib və JavaScript irsi olaraq grandParent-a baxır

    JavaScript proto prototype object chain

  • JavaScript-də Spread və Rest operatorunun gücü
    codexC codex

    JavaScript-də üç nöqtə (...) operatorunu tez-tez görürük: bəzən massivləri kopyalayır, bəzən funksiyaya verilən arqumentləri toplayır, bəzən isə obyektlərdə “sehrli çubuq” kimi istifadə edirik.

    Bu operatorun iki əsas istifadəsi var: spread və rest. Hər ikisi eyni sintaksisə malik olsa da, fərqli kontekstlərdə fərqli davranırlar.

    Spread və Rest: fərqləri nədir?

    Sintaksis Adı Məqsəd Nümunə
    ... Spread İterable elementləri genişləndirir const copy = [...arr]
    ... Rest Bir neçə elementi bir araya toplayır function(...args) {}

    Massivləri kopyalamaq (Shallow Copy)

    const numbers = [1, 2, 3];
    const copy = [...numbers];
    

    Bu, numbers massivinin səthi kopyasını yaradır, yəni yeni bir massivdir və orijinala referans deyil.

    Massivləri birləşdirmək

    const more = [4, 5];
    const all = [...numbers, ...more]; // [1, 2, 3, 4, 5]
    

    Artıq .concat() istifadə etməyə ehtiyac yoxdur!

    Funksiya arqumentlərinə yaymaq

    const coords = [10, 20];
    function move(x, y) {
      console.log(`Moving to (${x}, ${y})`);
    }
    
    move(...coords); // move(10, 20)
    

    Obyektləri kopyalamaq və yeniləmək (React üçün faydalı)

    const user = { name: "Sam", age: 30 };
    const updatedUser = { ...user, age: 31 };
    

    Bu, user obyektinin yeni bir nüsxəsini yaradır və age sahəsini yeniləyir.

    Sətirləri iterable kimi genişləndirmək

    const chars = [..."hello"]; // ['h', 'e', 'l', 'l', 'o']
    

    Funksiya parametrlərində

    function logAll(...messages) {
      messages.forEach(msg => console.log(msg));
    }
    
    logAll("Hello", "World", "Again");
    // "Hello"
    // "World"
    // "Again"
    

    Massiv destrukturlaşdırması ilə

    const [first, ...others] = [1, 2, 3, 4];
    console.log(first);  // 1
    console.log(others); // [2, 3, 4]
    

    Obyekt destrukturlaşdırması ilə

    const { id, ...info } = { id: 1, name: "Sam", age: 30 };
    console.log(id);   // 1
    console.log(info); // { name: "Sam", age: 30 }
    

    Real dünyadan istifadə halları

    React: State-i immutable yeniləmək

    setUser(prev => ({ ...prev, age: prev.age + 1 }));
    

    Form əməliyyatları: sahələri birləşdirmək

    const handleChange = (e) => {
      setForm(prev => ({ ...prev, [e.target.name]: e.target.value }));
    };
    

    Utility funksiyaları

    function sum(...nums) {
      return nums.reduce((a, b) => a + b, 0);
    }
    

    Diqqət ediləcək nöqtələr

    Səthi kopyalar

    const nested = { a: { b: 2 } };
    const copy = { ...nested };
    copy.a.b = 99;
    console.log(nested.a.b); // 99
    

    Obyekt Spread-də sıra əhəmiyyətlidir

    const user = { name: "Sam" };
    const updated = { ...user, name: "Alex" }; // name: "Alex"
    

    Nəticə

    Spread və rest sintaksisi JavaScript-də kodunuzu daha təmiz, ifadəli və səhvsiz yazmağa kömək edir. Bu operatorlar React, utility kitabxanaları və vanilla JS-də geniş istifadə olunur. Onları düzgün başa düşmək və istifadə etmək hər bir JavaScript proqramçısı üçün vacibdir.

    JavaScript spread rest operators

  • TypeScript-də Generics
    codexC codex

    Mapped Types — TypeScript-in qabaqcıl xüsusiyyətlərindən biridir və mövcud obyektlərin açarlarını (yəni keyof) istifadə edərək yeni tip yarada bilməyə imkan verir. Bu xüsusiyyət əsasən reusable və dinamik tiplər yaratmaq üçün istifadə olunur.


    1. Əsas sintaksis və istifadə

    Mapped Type yaratmaq üçün aşağıdakı sintaksisdən istifadə olunur:

    type MyMappedType<T> = {
      [P in keyof T]: T[P];
    };
    

    Bu o deməkdir ki, T tipində olan obyektin hər bir açarı (P) üçün həmin açarın tipi saxlanılır.

    Məsələn:

    type User = {
      name: string;
      age: number;
    };
    
    type ReadonlyUser = {
      readonly [P in keyof User]: User[P];
    };
    
    // nəticə:
    // {
    //   readonly name: string;
    //   readonly age: number;
    // }
    

    2. Sadə misallar

    a) Readonly

    type Readonly<T> = {
      readonly [K in keyof T]: T[K];
    };
    

    b) Partial

    type Partial<T> = {
      [K in keyof T]?: T[K];
    };
    

    c) Required

    type Required<T> = {
      [K in keyof T]-?: T[K];
    };
    

    3. as ilə Key Rename (Advanced Feature)

    type RemoveUnderscore<T> = {
      [K in keyof T as K extends `_${infer R}` ? R : K]: T[K];
    };
    
    type User = {
      _id: string;
      name: string;
    };
    
    type CleanUser = RemoveUnderscore<User>;
    // Nəticə:
    // {
    //   id: string;
    //   name: string;
    // }
    

    Burada as operatoru ilə _${infer R} pattern-i ilə başlayan açarları R şəklində dəyişmişik.


    4. Record Mapped Type kimi

    type Record<K extends keyof any, T> = {
      [P in K]: T;
    };
    
    const roles: Record<"admin" | "user", boolean> = {
      admin: true,
      user: false,
    };
    

    5. Real həyatdan misal

    Form input-lar üçün model yaradın:

    type FormFields = {
      email: string;
      password: string;
    };
    
    type FormErrors = {
      [K in keyof FormFields]?: string;
    };
    

    Bu halda FormErrors tipində email və password sahələri olacaq, amma optional və dəyərləri string olacaq.

    TypeScript typescript generics

  • TypeScript-də Generics
    codexC codex

    Generics — TypeScript-də məlumatların tipini dinamik şəkildə müəyyən etmək üçün istifadə olunan bir vasitədir. Generics proqramlarımızı yenidən istifadə edilə bilən və tip təhlükəsizliyi təmin edən şəkildə yazmağımıza kömək edir.

    Bu konsept bizə funksiyalarda, interfeyslərdə, classlarda və tiplərdə konkret tip əvəzinə gələcəkdə təyin ediləcək tip dəyişəni (T, U, K, s.) istifadə etməyə imkan verir.


    💡 Niyə Generics istifadə olunur?

    Əgər bir funksiyanı müxtəlif tiplərlə işləyəcək şəkildə yazmaq istəyiriksə və həmçinin TypeScript-in tip yoxlamasından faydalanmaq istəyiriksə, Generics çox faydalıdır.


    🔹 Sadə Generics nümunəsi

    function identity<T>(value: T): T {
      return value;
    }
    
    const str = identity<string>("Hello");
    const num = identity<number>(42);
    

    Bu nümunədə identity funksiyası hər hansı tipdə (T) dəyər alır və onu geri qaytarır. Bu funksiyanı həm string, həm number, həm də başqa istənilən tiplərlə istifadə etmək olar.


    🔸 Generics ilə Array işlənməsi

    function getFirstElement<T>(arr: T[]): T {
      return arr[0];
    }
    
    const first = getFirstElement<string>(["apple", "banana"]);
    const firstNum = getFirstElement<number>([10, 20, 30]);
    

    Burada T[] generik array-dir. Hansı tipdə array versəniz, TypeScript həmin tipdə cavab qaytaracaq.


    🔹 Generics ilə Interface və Type-lar

    interface Box<T> {
      content: T;
    }
    
    const stringBox: Box<string> = { content: "salam" };
    const numberBox: Box<number> = { content: 123 };
    

    Burada Box<T> interfeysi istənilən tipdə məlumat saxlamaq üçün generik olaraq təyin olunub.


    🔹 Generics ilə Class

    class Container<T> {
      private value: T;
    
      constructor(val: T) {
        this.value = val;
      }
    
      getValue(): T {
        return this.value;
      }
    }
    
    const container = new Container<string>("Data");
    console.log(container.getValue()); // "Data"
    

    Bu nümunədə Container class-ı generikdir və istənilən tipdə məlumat saxlaya bilir.


    🔸 Bir neçə tip dəyişəni ilə Generics

    function merge<T, U>(obj1: T, obj2: U): T & U {
      return { ...obj1, ...obj2 };
    }
    
    const merged = merge({ name: "Ali" }, { age: 25 });
    // merged: { name: "Ali", age: 25 }
    

    merge funksiyası iki fərqli tip qəbul edir və onların birləşməsini qaytarır.


    🔹 Tip məhdudiyyətləri (Constraints)

    Bəzən generik tipin müəyyən xüsusiyyətləri olmasını istəyə bilərik. Bu zaman extends istifadə olunur:

    function logLength<T extends { length: number }>(value: T): void {
      console.log(value.length);
    }
    
    logLength("Salam"); // 5
    logLength([1, 2, 3]); // 3
    

    Bu nümunədə T tipi yalnız length xüsusiyyətinə sahib olan tiplərlə məhdudlaşdırılıb.


    🔹 keyof Operatoru

    keyof operatoru bir obyektin açarlarını (key) tip kimi əldə etməyə imkan verir.

    interface Person {
      name: string;
      age: number;
    }
    
    type PersonKeys = keyof Person; // "name" | "age"
    

    Bu, xüsusilə dinamik açarlarla işləyərkən faydalıdır:

    function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
      return obj[key];
    }
    
    const person = { name: "Ali", age: 30 };
    const name = getProperty(person, "name"); // "Ali"
    

    🔹 infer və Conditional Types

    Conditional types tip əsaslı şərti ifadələr yaratmağa imkan verir. infer isə bu şərtlər daxilində tip çıxarmağa (inference) kömək edir.

    infer ilə tip çıxarma

    type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
    
    type Num = ReturnType<() => number>; // number
    type Str = ReturnType<(x: string) => string>; // string
    

    Burada infer R funksiyanın dönüş tipini çıxarır.

    Flatten nümunəsi

    type Flatten<T> = T extends Array<infer U> ? U : T;
    
    type Str = Flatten<string[]>; // string
    type Num = Flatten<number>;   // number
    

    Əgər T array tipidirsə, onun element tipini çıxarır, əks halda T-ni olduğu kimi saxlayır.


    🔹 Default Generic parametrlər

    Generik parametrlər üçün default (susmaya görə) dəyərlər təyin etmək mümkündür:

    function createArray<T = number>(length: number, value: T): T[] {
      return new Array(length).fill(value);
    }
    
    const numberArray = createArray(3, 0); // [0, 0, 0]
    const stringArray = createArray<string>(3, "hello"); // ["hello", "hello", "hello"]
    

    Burada T üçün default olaraq number tipi təyin edilib.


    ✅ Generics-in Üstünlükləri

    Üstünlük İzah
    🔁 Yenidən istifadə Eyni funksiya və ya sinif müxtəlif tiplərlə işləyə bilir.
    🔐 Tip təhlükəsizliyi Giriş və çıxış tipləri dəqiq müəyyənləşir.
    📦 Daha az təkrar kod Eyni əməliyyatı fərqli tiplərlə etmək üçün ayrıca funksiyalara ehtiyac yoxdur.

    📌 Nəticə

    Generics TypeScript-də çox güclü bir vasitədir və proqramların daha elastik, tip təhlükəsiz və yenidən istifadə oluna bilən olmasını təmin edir.

    Əgər siz funksiyalarınızın və strukturlarınızın tiplərini gələcəkdə təyin etmək istəyirsinizsə və təkrarı azaltmaq istəyirsinizsə — Generics istifadə etməyiniz tövsiyə olunur.

    TypeScript typescript generics

  • TypeScript-də type və interface
    codexC codex

    TypeScript statik tip təyin etmə imkanı verən JavaScript üzərində genişlənmiş bir proqramlaşdırma dilidir. Bu dildə məlumat strukturlarını daha aydın və təhlükəsiz şəkildə təsvir etmək üçün iki əsas vasitə var: type və interface.

    Bunların hər ikisi obyektlərin və verilən strukturlarının formasını təsvir etmək üçün istifadə olunur. Ancaq aralarında bəzi fərqli imkanlar və istifadə məqsədləri mövcuddur.


    🔹 interface nədir?

    interface – Obyektlərin strukturunu müəyyən etmək üçün istifadə olunur. Bir obyekt hansı sahələrə (fields) malik olacaq, onların tipi nə olacaq və hansılar məcburidir – bunlar interfeyslə müəyyənləşdirilir.

    Nümunə:

    interface Person {
      name: string;
      age: number;
      isStudent?: boolean; // optional field
    }
    

    Burada Person adlı interfeys name, age və istəyə bağlı isStudent sahələrini müəyyən edir.


    🔹 type nədir?

    type daha geniş imkanlara malikdir. O, həm obyektləri, həm də primitiv tipləri, birlik tipləri (union types), kəsişmə tipləri (intersection types) və tuple-ları təsvir edə bilər.

    Nümunə:

    type Person = {
      name: string;
      age: number;
    };
    

    Bu da interface-ə bənzər bir strukturdur, lakin type ilə aşağıdakıları da edə bilərik:

    Union Type (bir neçə növdən biri):

    type Status = "success" | "error" | "loading";
    

    Intersection Type (birləşmiş struktur):

    type Address = {
      city: string;
    };
    
    type Employee = Person & Address;
    

    ✅ Ortalıq Oxşarlıqları

    İmkan type interface
    Obyekt strukturu yaratmaq ✅ ✅
    Miras alma (inheritance) ✅ ✅
    Union və intersection yaratmaq ✅ ❌
    Tuple və primitive növləri müəyyənləşdirmək ✅ ❌
    Yenidən açılıb sahə əlavə etmək ❌ ✅ (Declaration merging)

    🔸 interface və type fərqləri

    Fərq type interface
    Quraşdırılmış genişlənmə type & operatoru ilə genişlənir interface birbaşa extends ilə genişlənə bilər
    Union, Intersection Tam dəstəklənir Dəstəklənmir
    Declaration merging (təkrar elan etmə) Olmaz Olur
    Primitiv tipləri təyin etmək Mümkündür (type Age = number) Mümkün deyil

    🔹 Hansını nə vaxt istifadə etməli?

    • Sadəcə obyekt strukturu təsvir edirsinizsə, interface istifadə etmək tövsiyə olunur.
    • Əgər union, intersection, primitiv və ya tuple növləri ilə işləyirsinizsə, type daha uyğun olar.
    • Üçüncü tərəf kitabxanalarında (React, Express) tez-tez interface istifadə olunur.

    ✅ Real dünya nümunəsi

    interface User {
      id: number;
      name: string;
    }
    
    type Role = "admin" | "user" | "guest";
    
    type UserWithRole = User & {
      role: Role;
    };
    

    Burada həm interface, həm də type birlikdə istifadə olunub.


    📌 Nəticə

    TypeScript-də type və interface hər ikisi strukturların və məlumatların təhlükəsiz işlənməsi üçün çox faydalıdır. Onların düzgün seçilməsi kodun daha oxunaqlı, yenidən istifadə oluna bilən və davamlı olmasını təmin edir.

    Əgər sadə obyekt strukturu ilə işləyirsinizsə – interface, daha kompleks tip təriflərinə ehtiyac varsa – type istifadə edin.

    TypeScript types interfaces typescript

  • Oracle SQL-də agregat funksiyalar
    codexC codex

    Agregat funksiyalar, Oracle SQL-də bir və ya bir neçə sətirdən ibarət məlumatları analiz etmək və ümumi nəticə çıxarmaq üçün istifadə olunur. Bu funksiyalar cədvəllərdəki dəyərləri qruplaşdırmaq, hesablamaq və filtrasiya etmək imkanı verir.

    Aşağıdakı ən çox istifadə olunan agregat funksiyalarla tanış olaq:

    İlk öncə misalları rahat göstərmək üçün employees adından cədvəl yaradaq və məlumatları ora əlavə edək

    EMPLOYEE_ID NAME SALARY DEPARTMENT_ID
    1 John Smith 3500 10
    2 Jane Doe 1600 10
    3 Emily Davis 2000 20
    4 Michael Brown 2500 30
    CREATE TABLE employees (
        employee_id NUMBER PRIMARY KEY,
        name VARCHAR2(100),
        salary NUMBER,
        department_id NUMBER
    );
    
    INSERT INTO employees (employee_id, name, salary, department_id)
    VALUES 
        (1, 'John Smith', 3500, 10),
        (2, 'Jane Doe', 1600, NULL),
        (3, 'Emily Davis', 2000, 20),
        (4, 'Michael Brown', 2500, 30);
    

    🔹 COUNT() – Sətirlərin sayını hesablayır

    Bu funksiya müəyyən bir sütundakı və ya bütün cədvəldəki sətirlərin sayını verir.

    Sintaksis:

    SELECT COUNT(*) FROM employees; --4
    

    Bütün işçilərin sayını qaytarır.

    Sütun səviyyəsində:

    SELECT COUNT(department_id) FROM employees; --3
    

    NULL olmayan department_id sütunlarının sayını qaytarır.


    🔹 SUM() – Toplam hesablayır

    Bu funksiya ədədi dəyərləri toplayır.

    SELECT SUM(salary) FROM employees; --9600
    

    Bütün işçilərin ümumi maaşını qaytarır.


    🔹 AVG() – Orta dəyəri hesablayır

    Bu funksiya ədədi sütun üzrə orta (average) dəyəri verir.

    SELECT AVG(salary) FROM employees; --2400
    

    Bütün işçilərin orta maaşını göstərir.


    🔹 MIN() – Ən kiçik dəyəri tapır

    Ən aşağı ədədi və ya əlifba sıralamasına görə minimum dəyəri qaytarır.

    SELECT MIN(salary) FROM employees; --1600
    

    Ən az maaşı olan işçinin maaşını qaytarır.

    SELECT MIN(name) FROM employees; --Emily Davis
    

    Əlifba sırasına görə ilk gələn adı göstərir.


    🔹 MAX() – Ən böyük dəyəri tapır

    Ən yüksək dəyəri qaytarır.

    SELECT MAX(salary) FROM employees; --3500
    

    Ən yüksək maaşı göstərir.


    🔸 GROUP BY ilə agregat funksiyalar

    Agregat funksiyaları GROUP BY ilə birlikdə istifadə edərək məlumatları qruplar üzrə analiz etmək mümkündür.

    SELECT department_id, AVG(salary)
    FROM employees
    GROUP BY department_id;
    

    Hər şöbə üçün orta maaş göstərilir.


    🔸 HAVING ilə agregat filtr

    Agregat nəticələri filtrasiya etmək üçün HAVING istifadə olunur. WHERE fərdi sətirlər üçün, HAVING isə GROUP BY nəticələri üçün tətbiq edilir.

    SELECT department_id, COUNT(*)
    FROM employees
    GROUP BY department_id
    HAVING COUNT(*) > 5;
    

    Yalnız 5-dən çox işçisi olan şöbələri göstərir.


    📌 Nəticə

    Oracle SQL-də agregat funksiyalar məlumatların xülasəsini çıxarmaq, ümumi mənzərəni görmək və qruplar üzrə analiz aparmaq üçün çox faydalıdır. GROUP BY, HAVING kimi əmr və funksiyalarla birlikdə istifadə olunduqda, çox güclü hesabatlar və analizlər aparmaq mümkündür.

    Oracle oracle sql aggregate avg sum

  • Oracle SQL-də JOIN əməliyyatları (Birləşdirmələr)
    codexC codex

    Verilənlər bazasında məlumatlar adətən normalizasiya edilmiş, yəni müxtəlif cədvəllərdə saxlanılır. Bu cədvəlləri əlaqələndirmək üçün JOIN əməliyyatlarından istifadə olunur. Oracle SQL-də bir neçə növ JOIN mövcuddur və hər biri fərqli ehtiyaclara cavab verir.


    🔗 1. INNER JOIN – Daxili birləşdirmə

    INNER JOIN iki və ya daha çox cədvəldə yalnız uyğun gələn (ortaq açar dəyəri olan) sətirləri birləşdirir. Nəzəri olaraq, inner join SQL sorğusu iki cədvəl arasında müqayisə edilən sətrlərin hamısının eyni dəyərlərə malik olması tələb olunur. Nəticədə, yalnız uyğunluq olan sətrləri nəticəyə əlavə edir.

    image (1).jpg

    Nümunə üçün iki cədvəli düşünək:

    Cədvəl 1: sifarişlər (orders)

    order_id customer_id goods_name order_date
    101 1 Laptop 2024-05-01
    102 1 Telefon 2024-05-03
    103 2 Tablet 2024-05-02
    104 3 Kamera 2024-05-04
    105 3 Klaviatura 2024-05-05

    Cədvəl 2: müştərilər (customers)

    customer_id name surname
    1 Ali Məmmədov
    2 Nigar Əliyeva
    3 Cavid Məmmədli

    Bu iki cədvəli birləşdirmək üçün aşağıdakı SQL sorğusunu istifadə edə bilərik:

    SELECT customers.name, customers.surname, orders.goods_name, orders.order_date
    FROM orders
    INNER JOIN customers ON customers.customer_id = orders.customer_id;
    

    Bu sorğunun nəticəsi belə olacaq:

    name surname goods_name order_date
    Ali Məmmədov Laptop 2024-05-01
    Ali Məmmədov Telefon 2024-05-03
    Nigar Əliyeva Tablet 2024-05-02
    Cavid Məmmədli Kamera 2024-05-04
    Cavid Məmmədli Klaviatura 2024-05-05

    Bu sorğu “müştərilər” və “sifarişlər” cədvəllərini customer_id sütunu əsasında birləşdirir. Nəticədə, hər bir sifarişin hansı müştəri tərəfindən verildiyi və sifariş tarixi ilə birlikdə müştəri adını və soyadını göstərir.

    -- müştərilərilər cədvəlinin yaradılması              
    CREATE TABLE customers (
        customer_id NUMBER PRIMARY KEY,
        name VARCHAR2(50),
        surname VARCHAR2(50)
    );
    
    -- müştərilər cədvəlinin doldurulması
    INSERT INTO customers (customer_id, name, surname) VALUES
    (1, 'Ali', 'Məmmədov'),
    (2, 'Nigar', 'Əliyeva'),
    (3, 'Cavid', 'Məmmədli');
    
    -- sifarişlər cədvəlinin yaradılması
    CREATE TABLE orders (
        order_id NUMBER PRIMARY KEY,
        customer_id NUMBER,
        goods_name VARCHAR2(100),
        order_date DATE,
        FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
    );
    
    -- sifarişlər cədvəlinin doldurulması
    INSERT INTO orders (order_id, customer_id, goods_name, order_date) VALUES
    (101, 1, 'Laptop', DATE '2024-05-01'),
    (102, 1, 'Telefon', DATE '2024-05-03'),
    (103, 2, 'Tablet', DATE '2024-05-02'),
    (104, 3, 'Kamera', DATE '2024-05-04'),
    (105, 3, 'Klaviatura', DATE '2024-05-05');
    


    🔍 2. LEFT JOIN – Sol birləşdirmə

    LEFT JOIN sol cədvəldəki bütün sətirləri, sağ cədvəldə isə yalnız uyğun gələnləri birləşdirir. Əgər sağ tərəfdə uyğun sətir yoxdursa, həmin sütunlarda NULL göstərilir.

    image.jpg

    İki cədvəl nümunəsi:

    employees cədvəli:

    employee_id name department_id
    1 John Smith 10
    2 Jane Doe NULL
    3 Emily Davis 20
    4 Michael Brown 30

    departments cədvəli:

    department_id department_name
    10 IT
    20 HR
    30 Finance
    SELECT employees.employee_id, employees.name, departments.department_name
    FROM employees
    LEFT JOIN departments
    ON employees.department_id = departments.department_id;
    

    Bu sorğunun nəticəsi belə olacaq:

    employee_id name department_name
    1 John Smith IT
    2 Jane Doe NULL
    3 Emily Davis HR
    4 Michael Brown Finance

    CREATE TABLE departments (
        department_id NUMBER PRIMARY KEY,
        department_name VARCHAR2(100)
    );
    
    INSERT INTO departments (department_id, department_name)
    VALUES 
        (10, 'IT'),
        (20, 'HR'),
        (30, 'Finance');
    
    
    CREATE TABLE employees (
        employee_id NUMBER PRIMARY KEY,
        name VARCHAR2(100),
        department_id NUMBER,
        FOREIGN KEY (department_id) REFERENCES departments(department_id)
    );
    
    INSERT INTO employees (employee_id, name, department_id)
    VALUES 
        (1, 'John Smith', 10),
        (2, 'Jane Doe', NULL),
        (3, 'Emily Davis', 20),
        (4, 'Michael Brown', 30);
    


    🔎 3. RIGHT JOIN – Sağ birləşdirmə

    RIGHT JOIN sağ cədvəldəki bütün sətirləri, sol cədvəldə isə uyğun gələnləri birləşdirir. Əgər sol cədvəldə uyğun gələn sətir yoxdursa, onda nəticə dəstində sol cədvəldəki sütunlar üçün NULL dəyərləri olacaq.

    e602b870-cd54-4536-a665-283a9b565074-image.png

    Bir nümunə ilə izah edək. İki cədvəlimiz var:

    • Orders (Sifarişlər)
    • Customers (Müştərilər)

    Orders cədvəli:

    OrderID CustomerID OrderDate
    1 1001 2023-01-15
    2 1002 2023-02-20
    3 1003 2023-03-12

    Customers cədvəli:

    CustomerID CustomerName
    1001 Ali
    1002 Ayşe
    1004 Mehmet

    RIGHT JOIN sorğusu ilə Orders və Customers cədvəllərini birləşdirək:

    SELECT Orders.OrderID, Orders.OrderDate, Customers.CustomerName
    FROM Orders
    RIGHT JOIN Customers ON Orders.CustomerID = Customers.CustomerID;
    

    Bu sorğunun nəticəsi belə olacaq:

    OrderID OrderDate CustomerName
    1 2023-01-15 Ali
    2 2023-02-20 Ayşe
    NULL NULL Mehmet

    Göründüyü kimi, Customers cədvəlindəki bütün müştərilər nəticədə göstərilir, hətta Orders
    cədvəlində uyğun gələn sifariş olmadıqda belə. Mehmet üçün sifariş məlumatı olmadığından, onun üçün
    NULL dəyərləri qaytarılır.

    CREATE TABLE customers (
        CustomerID NUMBER PRIMARY KEY,
        CustomerName VARCHAR2(100)
    );
    
    INSERT INTO customers (CustomerID, CustomerName)
    VALUES 
        (1001, 'Ali'),
        (1002, 'Ayşe'),
        (1004, 'Mehmet');
    
    CREATE TABLE orders (
        OrderID NUMBER PRIMARY KEY,
        CustomerID NUMBER,
        OrderDate DATE
    );
    
    INSERT INTO orders (OrderID, CustomerID, OrderDate)
    VALUES 
        (1, 1001, TO_DATE('2023-01-15', 'YYYY-MM-DD')),
        (2, 1002, TO_DATE('2023-02-20', 'YYYY-MM-DD')),
        (3, 1003, TO_DATE('2023-03-12', 'YYYY-MM-DD'));
    


    🔄 4. FULL OUTER JOIN – Tam birləşdirmə

    Bu JOIN həm sol, həm də sağ cədvəldəki bütün sətirləri qaytarır. Uyğun gəlməyənlər üçün NULL istifadə olunur.

    Nümunə:

    SELECT employees.name, departments.name
    FROM employees
    FULL OUTER JOIN departments
    ON employees.dept_id = departments.id;
    

    🔁 5. CROSS JOIN – Çarpaz birləşdirmə

    CROSS JOIN hər bir sətiri digər cədvəldəki bütün sətirlərlə birləşdirir. Bu zaman kartesian hasil yaranır.

    Nümunə:

    SELECT A.name, B.name
    FROM tableA A
    CROSS JOIN tableB B;
    

    Əgər tableA 3 sətir, tableB 2 sətirdirsə, nəticə 6 sətirdən ibarət olacaq (3 × 2).


    💡 Alternativ JOIN Sintaksisi

    Oracle-da daha əvvəlki dövrlərdə istifadə olunan sintaksis belə idi:

    SELECT e.name, d.name
    FROM employees e, departments d
    WHERE e.dept_id = d.id;
    

    Bu yazılış INNER JOIN-in qısa formasıdır. Amma müasir SQL-də açıq şəkildə JOIN yazmaq daha oxunaqlı və texniki cəhətdən üstün sayılır.


    ✅ Nəticə

    JOIN Növü İzahı
    INNER JOIN Hər iki cədvəldə uyğun olan sətirləri qaytarır
    LEFT JOIN Sol cədvəldə olan bütün sətirləri, uyğun olanları sağdan
    RIGHT JOIN Sağ cədvəldə olan bütün sətirləri, uyğun olanları soldan
    FULL OUTER JOIN Hər iki cədvəldə olan bütün sətirləri qaytarır
    CROSS JOIN Bütün mümkün birləşmələri (kartesian hasil) qaytarır
    Oracle oracle innerjoin leftjoin rightjoin sql

  • JavaScript-də Prototype Chain (Prototip Zənciri)
    codexC codex

    🧬 Object.create() vasitəsilə İrsi əlaqə (Inheritance)

    JavaScript-də irsi əlaqə qurmağın başqa bir güclü və sadə yolu Object.create() metodudur. Bu metod vasitəsilə yeni bir obyekt yaradılır və bu obyektin prototipi kimi istədiyimiz digər bir obyekt təyin edilir.

    Bu üsul klassik constructor-lar və prototype zənciri qurmaqdan daha sadə və daha oxunaqlıdır.

    🧪 Nümunə:

    const animal = {
      eats: true,
      walk() {
        console.log("Animal is walking");
      }
    };
    
    const rabbit = Object.create(animal);
    rabbit.jumps = true;
    
    console.log(rabbit.eats);  // true (animal-dan miras alır)
    rabbit.walk();             // "Animal is walking"
    console.log(rabbit.jumps); // true (öz xüsusiyyəti)
    

    Bu nümunədə:

    • rabbit obyektini Object.create(animal) ilə yaratmışıq.
    • rabbit obyektində eats xüsusiyyəti yoxdur, lakin animal onun prototipidir, ona görə həmin xüsusiyyətə çatmaq mümkündür.
    • Bu, prototip zəncirinin bir hissəsidir və miras alınmış metod və xüsusiyyətlər animal obyektindən gəlir.

    ✅ Object.create() istifadəsinin üstünlükləri:

    • Daha sadə sintaksis.
    • Klassik constructor funksiyalarına ehtiyac olmadan obyekt əsaslı irsilik qurmaq imkanı.
    • Müxtəlif obyektlər arasında açıq şəkildə əlaqə yaratmaq olur.
    • Test və prototipləşdirmə üçün çox uyğundur və çevikdir.

    Beləliklə, Object.create() JavaScript-də irsi əlaqənin daha bir güclü vasitəsidir və Prototype Chain anlayışının birbaşa tətbiqini nümayiş etdirir. Bu metod xüsusilə funksional proqramlaşdırma yanaşmalarında və modul sistemlərində tez-tez istifadə olunur.

    JavaScript proto prototype object chain

  • JavaScript-də Prototype Chain (Prototip Zənciri)
    codexC codex

    JavaScript obyekt yönümlü proqramlaşdırma (OOP) yanaşmasını prototip əsaslı sistem vasitəsilə həyata keçirir. Bu, digər obyektlərin xüsusiyyətlərini miras almaq üçün klassik classlardan istifadə etmədən, obyektlər arasında birbaşa əlaqə qurulmasına imkan verir. Bu prosesə Prototype Chain, yəni Prototip Zənciri deyilir.


    🔧 Prototip nədir?

    JavaScript-də hər bir obyektin arxasında [[Prototype]] adlı gizli bir xüsusiyyət var. Bu xüsusiyyət digər obyektə (və ya null-a) istinad edir. Əgər siz bir obyektin içində müəyyən xüsusiyyət və ya metod axtarırsınızsa, JavaScript əvvəlcə həmin obyektin özündə yoxlayır, əgər tapa bilmirsə, onun prototipində axtarmağa davam edir. Bu proses Prototip Zəncirini təşkil edir.


    🔗 Prototip zəncirinin iş prinsipi

    Tutaq ki, bir obyektin içində sayHello() adlı metod yoxdur. JavaScript bu metodu həmin obyektin [[Prototype]]-ində axtarır. Əgər orada da tapa bilmirsə, növbəti prototipə keçir və bu proses null-a qədər davam edir.


    🧪 Nümunə ilə izah

    const animal = {
      eats: true,
      walk() {
        console.log("Animal is walking");
      }
    };
    
    const rabbit = {
      jumps: true
    };
    
    rabbit.__proto__ = animal; // rabbit-in prototipi animal-dır
    
    console.log(rabbit.jumps); // true (öz xüsusiyyəti)
    console.log(rabbit.eats);  // true (animal-dan miras alır)
    rabbit.walk();             // "Animal is walking"
    

    Bu nümunədə rabbit obyektində eats xüsusiyyəti yoxdur. Lakin animal onun prototipidir, ona görə rabbit.eats sorğusu true nəticəsini qaytarır.


    📐 Prototip zəncirində dərinlik

    const creature = {
      breathes: true
    };
    
    const animal = {
      eats: true,
      __proto__: creature
    };
    
    const rabbit = {
      jumps: true,
      __proto__: animal
    };
    
    console.log(rabbit.breathes); // true (creature-dan gəlir)
    

    Burada rabbit → animal → creature zənciri qurulub. rabbit.breathes çağırışı 3 səviyyəli zəncir vasitəsilə true cavabı verir.


    🔁 Prototiplər və Constructor funksiyalar

    function Person(name) {
      this.name = name;
    }
    
    Person.prototype.sayHello = function () {
      console.log("Salam, mənim adım " + this.name);
    };
    
    const user = new Person("Elvin");
    user.sayHello(); // Salam, mənim adım Elvin
    

    Burada user obyektinin sayHello metodu özündə yoxdur. JavaScript onun konstruktorunun (Person) prototype obyektinə baxır və oradan tapır.


    🧬 Object.prototype və Zəncirin sonu

    JavaScript-də bütün obyektlər nəticədə Object.prototype-dən miras alır.

    const obj = {};
    console.log(obj.toString()); // [object Object]
    

    Burada toString metodu obj-də yoxdur, lakin Object.prototype-də olduğu üçün işləyir. Ən sonda zəncir null ilə bitir:

    console.log(Object.prototype.__proto__); // null
    

    ⚠️ Diqqət: __proto__ istifadəsi

    __proto__ hələ də geniş istifadə olunur, lakin standart və tövsiyə edilən üsul Object.getPrototypeOf() və Object.setPrototypeOf() metodlarıdır.

    Object.setPrototypeOf(rabbit, animal);
    console.log(Object.getPrototypeOf(rabbit)); // animal
    

    📌 Nəticə

    • Prototip Zənciri obyektlər arasında əlaqə quraraq xüsusiyyət və metodları miras almağa imkan verir.
    • Obyektdə axtarılan xüsusiyyət tapılmadıqda, onun prototipində axtarılır və bu, null-a qədər davam edir.
    • Function.prototype, Object.prototype və digər daxili obyektlər bu zəncirin hissələridir.
    • Zəncir çox dərinə getsə belə, performans baxımından effektiv şəkildə işləyir.
    • __proto__ istifadə olunsa da, müasir və təhlükəsiz metodlar Object.getPrototypeOf() və Object.setPrototypeOf() hesab olunur.

    Təşəkkürlər ColorCode gözəl izahlı video üçün

    JavaScript proto prototype object chain
  • 1 / 1
  • Daxil ol

  • Sizin hesabınız yoxdur? Qeydiyyatdan keç

  • Axtarış etmək üçün daxil olun və ya qeydiyyatdan keçin.
  • İlk yazı
    Son yazı
0
  • Kateqoriyalar
  • Ən yeni
  • Teqlər
  • Populyar