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

codex

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

Yazı

Ən yeni

  • JavaScript-də document və window obyektləri
    codexC codex

    Veb proqramlaşdırmada JavaScript ilə işləyərkən iki əsas obyektə tez-tez rast gəlirik: window və document. Bu obyektlər JavaScript-in brauzer mühitində necə işlədiyini anlamaq mühüm rol oynayır. Gəlin onları yaxından tanıyaq.


    window obyekti nədir?

    window obyekti JavaScript-də qlobal obyekt sayılır. Brauzerdə açılan hər bir səhifə üçün window obyektinin bir nüsxəsi yaradılır. Bu obyekt brauzer pəncərəsini (və ya tabını) təmsil edir və onun daxilində bir çox faydalı metodlar və xüsusiyyətlər mövcuddur.

    Xüsusiyyətləri və metodları:

    • window.alert() – istifadəçiyə xəbərdarlıq mesajı göstərmək
    • window.setTimeout() – müəyyən vaxtdan sonra kodun icrasını planlamaq
    • window.location – cari URL məlumatlarına daxil olmaq və dəyişmək
    • window.innerWidth, window.innerHeight – brauzerin daxili ölçülərini əldə etmək
    • və sairə…

    Əslində, JavaScript-də yazdığınız qlobal dəyişənlər və funksiyalar avtomatik olaraq window obyektinin bir hissəsinə çevrilir:

    var x = 10;
    console.log(window.x); // 10
    

    document obyekti nədir?

    document obyekti window obyektinin bir hissəsidir və HTML sənədini təmsil edir. Yəni, veb səhifənin strukturuna (DOM – Document Object Model) daxil olmaq, onu oxumaq və ya dəyişdirmək üçün istifadə olunur.

    Əsas metodlar və xüsusiyyətlər:

    • document.getElementById() – HTML elementini ID ilə tapmaq
    • document.querySelector() – CSS selektorları ilə element seçmək
    • document.title – səhifənin başlığını oxumaq və ya dəyişmək
    • document.body, document.head – səhifənin əsas struktur hissələrinə çıxış
    • və sairə…
    const title = document.getElementById("my-title");
    title.textContent = "Yeni Başlıq";
    

    window və document arasındakı fərqlər

    Özəllik window document
    Nəyi təmsil edir? Brauzer pəncərəsini HTML sənədini
    Qlobal obyekt Bəli Xeyr, window içindədir
    Əsas istifadə sahəsi Brauzer ilə əlaqəli funksiyalar (alert, setTimeout, location və s.) DOM ilə işləmək, HTML strukturu ilə əlaqə
    Məsuliyyət sahəsi Ümumi pəncərə və interfeys idarəsi Səhifə məzmunu və strukturu

    Bir-birinə necə bağlıdırlar?

    document obyekti əslində window obyektinin daxilində mövcuddur:

    console.log(window.document === document); // true
    

    Bu, o deməkdir ki, document hər zaman window obyektinin içində yerləşir, lakin biz onu birbaşa da çağıraraq istifadə edə bilərik.


    JavaScript-də window və document obyektləri veb səhifənin və brauzer mühitinin idarəsi üçün əsas komponentlərdir.

    • window – ümumi brauzer pəncərəsini,
    • document – səhifənin HTML strukturu və məzmununu təmsil edir.

    Bu iki obyektin fərqini və hansı vəziyyətdə hansından istifadə edilməli olduğunu başa düşmək, daha təmiz və effektiv JavaScript kodu yazmaq üçün vacibdir.

    Front-end document window dom browser

  • ARIA Label nədir və necə istifadə etməliyik?
    codexC codex

    Web saytlarının daha əlçatan və istifadəçi yönümlü olması üçün a11y (accessibility) yanaşması vacib rol oynayır. Bu yanaşmanın əsas hissələrindən biri də aria-label atributudur. Bəs bu atribut nə üçündür və onu hansı hallarda istifadə etməliyik?


    aria-label nə işə yarayır?

    aria-label atributu elementin görmə qabiliyyəti məhdud olan istifadəçilər üçün ekran oxuyucular vasitəsilə səsləndiriləcək mətnini təyin edir. Yəni, bu atribut vizual olaraq istifadəçiyə göstərilməsə də, ekran oxuyucu proqram bu məlumatı səsləndirir.

    Məsələn, təkcə ikonası olan bir düyməni götürək:

    <button aria-label="Sil">
      <TrashIcon />
    </button>
    

    Bu halda ekran oxuyucu “Sil düyməsi” kimi səsləndirəcək. Halbuki istifadəçi ekranda yalnız zibil qutusunu görür.


    Nə zaman istifadə olunmalıdır?

    • Görünən mətn olmayan ikonalı düymələrdə
    • Təkcə simvol və ya şəkil olan linklərdə
    • Özəl dizayn edilmiş (custom) checkbox, switch və ya radio komponentlərində
    • Form elementlərində label etiketi olmayan hallarda
    • Mobil tətbiqlərdəki Floating Action Button (FAB) tipli düymələrdə

    Nə zaman istifadə olunmamalıdır?

    aria-label atributu, əgər həmin elementdə artıq görünən mətn varsa, istifadə edilməməlidir. Çünki bu halda aria-label həmin mətnin əvəzində oxunacaq və istifadəçini çaşdıra bilər.

    Yanlış nümunə:

    <button aria-label="Təsdiqlə">Formu Göndər</button>
    

    Ekran oxuyucu burada “Təsdiqlə” deyəcək, halbuki istifadəçi “Formu Göndər” yazısını görür.

    Əgər artıq mətn varsa, aria-label deyil, ehtiyac olarsa aria-describedby və ya aria-labelledby istifadə etmək daha məqsədəuyğundur.


    aria-* atributlarının fərqləri

    Atribut Təyinatı
    aria-label Görünməyən, lakin ekran oxuyucular üçün vacib qısa ad
    aria-labelledby Başqa elementin ID-sinə əsaslanaraq adı təyin edir
    aria-describedby Əlavə izahat və ya köməkçi mətnləri ekran oxuyucular üçün göstərmək üçündür

    Tövsiyələr və yaxşı təcrübələr (best practices)

    • Dekorativ ikonalar üçün aria-hidden="true" istifadə edin.
    • Əgər komponent daxilində mətn varsa, əlavə aria-label verməyin.
    • İmkan daxilində semantic HTML komponentlərdən istifadə edin (<button>, <label> və s.).
    • Kodunuzu test etmək üçün axe, lighthouse, eslint-plugin-jsx-a11y kimi alətlərdən istifadə edin.
    • Screen reader ilə canlı testlər edin (NVDA, VoiceOver və s.).

    aria-label — sadə görünməsinə baxmayaraq, vəzifəsi kritik olan bir xüsusiyyətdir. Əlçatanlıq məqsədilə istifadə olunan bu atribut, düzgün tətbiq olunduqda saytınızı daha inklüziv və bütün istifadəçilər üçün uyğun hala gətirir.

    Unutmayın:

    Accessibility — sadəcə məhdudiyyətləri olan insanlar üçün deyil, hər kəs üçün daha yaxşı təcrübə yaratmaqdır.

    Front-end aria-label a11y aria-labelledby accessibility

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

    Proxy Pattern — obyektə birbaşa çıxışı nəzarət altında saxlamaq üçün istifadə olunan dizayn pattern-dir. Bu pattern-in əsas məqsədi, obyektə vasitəçi (proxy) vasitəsilə nəzarət etməkdir. JavaScript-də bu konsept həm real həyatda, həm də proqramlaşdırmada çox faydalıdır.

    Bu yazıda aşağıdakı Proxy Pattern növlərini incələyəcəyik:

    • Property Proxy
    • Protection Proxy
    • Virtual Proxy

    1. valueOf() və toString() ilə xüsusi tip obyektlər

    Aşağıdakı Percentage class-ı valueOf və toString metodları ilə say kimi istifadə edilə bilən obyekt yaradır:

    class Percentage {
      constructor(value) {
        this.value = value;
      }
    
      toString() {
        return `${this.value}%`;
      }
    
      valueOf() {
        return this.value / 100;
      }
    }
    
    let fivePercent = new Percentage(5);
    console.log(fivePercent.toString()); // "5%"
    console.log(`5% of 50 is ${50 * fivePercent}`); // 2.5
    

    ➡️ Bu, JavaScript-in type coercion xüsusiyyətindən yararlanır: valueOf() metodu çağrıldıqda obyektin rəqəmsal dəyəri kimi işlənir.


    2. Property Proxy – Dəyərlərə nəzarət və loglama

    Property classı ilə dəyərlərin dəyişməsinə nəzarət və loglama imkanı yaradılır:

    class Property {
      constructor(value, name = "") {
        this._value = value;
        this.name = name;
      }
    
      get value() {
        return this._value;
      }
    
      set value(newValue) {
        if (this._value === newValue) return;
        
        console.log(`Property ${this.name} changed from ${this._value} to ${newValue}`);
        this._value = newValue;
      }
    }
    
    class Creature {
      constructor() {
        this._agility = new Property(10, "agility");
      }
    
      get agility() {
        return this._agility.value;
      }
    
      set agility(newValue) {
        this._agility.value = newValue;
      }
    }
    
    let creature = new Creature();
    creature.agility = 15; // Property agility changed from 10 to 15
    creature.agility = 15; // No change
    console.log(creature.agility); // 15
    

    ✅ Fayda: Hər dəfə dəyər dəyişəndə loglama aparılır. Lazım olsa, undo sistemi və ya dəyişiklik tarixi də əlavə edilə bilər.


    3. Protection Proxy – Təhlükəsizlik nəzarəti

    Aşağıdakı nümunədə bir maşını yalnız yaşa uyğun olaraq sürməyə icazə verilir:

    class Car {
      drive() {
        console.log("Car is being driven");
      }
    }
    
    class CarProxy {
      constructor(driver) {
        this.driver = driver;
        this._car = new Car();
      }
    
      drive() {
        if (this.driver.age >= 16) {
          this._car.drive();
        } else {
          console.log("Driver is too young to drive");
        }
      }
    }
    
    class Driver {
      constructor(age) {
        this.age = age;
      }
    }
    
    let car1 = new CarProxy(new Driver(15));
    car1.drive(); // Driver is too young to drive
    
    let car2 = new CarProxy(new Driver(22));
    car2.drive(); // Car is being driven
    

    🔐 Protection Proxy sistemə yalnız uyğun istifadəçilərin çıxışını təmin edir. Məsələn, admin panelinə giriş, API endpoint-ə çıxış və s.


    4. Virtual Proxy – Tənbəl yükləmə (Lazy Loading)

    Image obyektinin yaddaşı çox istifadə edə biləcəyini fərz edək. Onu yalnız ilk dəfə lazım olduqda yaratmaq istərik:

    class Image {
      constructor(url) {
        this.url = url;
        console.log(`Image created with URL: ${this.url}`);
      }
    
      draw() {
        console.log(`Drawing image from ${this.url}`);
      }
    }
    
    class LazyImage {
      constructor(url) {
        this.url = url;
      }
    
      draw() {
        if (!this._image) {
          console.log(`Loading image from ${this.url}`);
          this._image = new Image(this.url);
        }
        this._image.draw();
      }
    }
    
    function drawImage(image) {
      console.log("About to draw image...");
      image.draw();
      console.log("Done drawing the image.");
    }
    
    let image = new LazyImage("https://example.com/image.jpg");
    drawImage(image);
    // Yalnız ilk dəfə draw çağırıldıqda Image yaradılır
    

    ⚡ Fayda: Lazım olmayan resursların istifadəsini gecikdirməklə performansı optimallaşdırır.


    Nəticə

    Proxy Pattern JavaScript-də çox güclü bir konseptdir. Bu pattern aşağıdakı hallarda çox faydalıdır:

    Növ Təsvir
    Property Proxy Mülkət dəyişikliklərinə nəzarət, loglama
    Protection Proxy Giriş nəzarəti və hüquq yoxlaması
    Virtual Proxy Resursların tənbəl yüklənməsi (lazy loading)

    Bu nümunələr real həyatda istər UI komponentləri, istərsə də API istəkləri, giriş kontrol sistemləri üçün praktik imkanlar yaradır.

    Dizayn nümunələri design proxy pattern

  • Bridge Pattern – Abstraksiya və İcranın Ayrılması
    codexC codex

    🧪 Tapşırıq

    Aşağıdakı kod nümunəsində Shape adlı əsas class-dan Square və Triangle class-ları yaradılır. Hər forma həm Vector (xəttlərlə) həm də Raster (piksel ilə) şəklində çəkilə bilər. Bu isə hər formanın iki fərqli versiyasının yaradılmasına səbəb olur:

    class Shape {
      constructor(name) {
        this.name = name;
      }
    }
    
    class Triangle extends Shape {
      constructor() {
        super('triangle');
      }
    }
    
    class Square extends Shape {
      constructor() {
        super('square');
      }
    }
    
    class VectorSquare extends Square {
      toString() {
        return 'Drawing square as lines';
      }
    }
    
    class RasterSquare extends Square {
      toString() {
        return 'Drawing square as pixels';
      }
    }
    
    // imagine VectorTriangle and RasterTriangle are here too
    

    Bu yanaşma çox sayda class-ın yaradılmasına səbəb olur və sistemin genişləndirilməsini çətinləşdirir. Hər yeni forma və render üsulu üçün yeni bir class əlavə etmək lazım gəlir. Bu, məhz Dekart hasili problemini yaradır:

    Formalar × Render üsulları = Çox sayda sinif

    Yuxarıdakı kodu elə refactor edin ki, Bridge Pattern-dən istifadə edərək VectorTriangle və RasterTriangle yaradıb kodu new Triangle(new RasterRenderer()); formada çağırdıqda cavabında Drawing Triangle as pixels alınsın.


    🧩 Həlli

    Çalışın ilk öncə özünüz həll edin sonra həllinə baxın


    Bu problemi Bridge Pattern ilə həll edə bilərik. Bu dizayn pattern-in məqsədi abstraksiyanı onun implementasiyasından ayırmaqdır. Bununla da hər iki tərəf müstəqil şəkildə inkişaf etdirilə bilər.

    // Renderer interfeysini təmsil edən baza class
    class Renderer {
      get whatToRenderAs() {
        throw new Error('whatToRenderAs not implemented');
      }
    }
    
    // Konkret Renderer-lər
    class VectorRenderer extends Renderer {
      get whatToRenderAs() {
        return 'lines';
      }
    }
    
    class RasterRenderer extends Renderer {
      get whatToRenderAs() {
        return 'pixels';
      }
    }
    
    // Baz forma classı— artıq rendereri qəbul edir
    class Shape {
      constructor(name, renderer) {
        this.name = name;
        this.renderer = renderer;
      }
    
      toString() {
        return `Drawing ${this.name} as ${this.renderer.whatToRenderAs}`;
      }
    }
    
    // Konkret formalar — yalnız ad və renderer qəbul edir
    class Triangle extends Shape {
      constructor(renderer) {
        super('Triangle', renderer);
      }
    }
    
    class Square extends Shape {
      constructor(renderer) {
        super('Square', renderer);
      }
    }
    

    ⚙️ İstifadə nümunəsi

    const triangle = new Triangle(new RasterRenderer());
    console.log(triangle.toString()); 
    // Output: Drawing Triangle as pixels
    
    const square = new Square(new VectorRenderer());
    console.log(square.toString()); 
    // Output: Drawing Square as lines
    

    Dizayn nümunələri design pattern bridge abstraction

  • Bridge Pattern – Abstraksiya və İcranın Ayrılması
    codexC codex

    c71ae996-8acc-4e98-94b3-ea51c28235f8-image.png

    Bridge Pattern (Körpü nümunəsi) — proqramlaşdırmada abstraksiyanı (istifadəçi səviyyəsində interfeys) onun icrasından (daxili işləmə qaydasından) ayırmaq üçün istifadə olunan dizayn nümunəsidir. Bu, hər iki tərəfin müstəqil şəkildə inkişaf etdirilməsinə imkan yaradır.

    Başqa sözlə, bu pattern “nə edirik” və “necə edirik” anlayışlarını bir-birindən ayırır.


    🧪 JavaScript-də Bridge Pattern nümunəsi

    // Abstraksiya
    class RemoteControl {
      constructor(device) {
        this.device = device;
      }
    
      togglePower() {
        if (this.device.isEnabled()) {
          this.device.disable();
        } else {
          this.device.enable();
        }
      }
    
      volumeUp() {
        this.device.setVolume(this.device.getVolume() + 10);
      }
    
      volumeDown() {
        this.device.setVolume(this.device.getVolume() - 10);
      }
    }
    
    // Genişləndirilmiş Abstraksiya
    class AdvancedRemoteControl extends RemoteControl {
      mute() {
        this.device.setVolume(0);
      }
    }
    
    // İcraçı interfeys
    class Device {
      constructor() {
        this.volume = 50;
        this.enabled = false;
      }
    
      isEnabled() {
        return this.enabled;
      }
    
      enable() {
        this.enabled = true;
      }
    
      disable() {
        this.enabled = false;
      }
    
      getVolume() {
        return this.volume;
      }
    
      setVolume(volume) {
        this.volume = volume;
      }
    }
    
    // Konkret İcraçılar
    class TV extends Device {
      constructor() {
        super();
      }
      // TV-yə xas əlavə metodlar buraya əlavə oluna bilər
    }
    
    class Radio extends Device {
      constructor() {
        super();
      }
      // Radioya xas əlavə metodlar buraya əlavə oluna bilər
    }
    

    🔍 Koda təhlil ilə baxış

    Komponent İzah
    RemoteControl Abstraksiya rolunu oynayır. Obyekti idarə etmək üçün ümumi metodlar təklif edir, lakin icranı device obyektinə ötürür.
    AdvancedRemoteControl Abstraksiyanı genişləndirir və əlavə imkanlar təqdim edir (məsələn, mute).
    Device İcraçı (Implementor) interfeysidir. Konkret cihazların davranışlarını müəyyən edir.
    TV və Radio Konkret icraçılar (Concrete Implementors). Device sinfini miras alaraq öz spesifik funksiyalarını əlavə edə bilərlər.

    ▶️ İstifadə nümunəsi

    const tv = new TV();
    const remote = new RemoteControl(tv);
    
    remote.togglePower();
    console.log(tv.isEnabled()); // true
    
    remote.volumeUp();
    console.log(tv.getVolume()); // 60
    
    const radio = new Radio();
    const advancedRemote = new AdvancedRemoteControl(radio);
    
    advancedRemote.togglePower();
    console.log(radio.isEnabled()); // true
    
    advancedRemote.mute();
    console.log(radio.getVolume()); // 0
    

    Burada RemoteControl istənilən Device tipli obyektlə işləyə bilir. Hər bir yeni cihaz üçün RemoteControl-u dəyişməyə ehtiyac yoxdur.


    🧠 Nəyə görə Bridge Pattern istifadə olunur?

    • Kodun genişləndirilməsi asanlaşır.
    • Yeni Device (məsələn, Projector) və ya yeni RemoteControl variantları əlavə etmək mümkündür.
    • Abstraksiya və implementasiya bir-birindən asılı deyil, bu da çeviklik və test ediləbilərlik verir.

    📊 Ümumi Xülasə

    Bridge Pattern, kodu aşağıdakı şəkildə strukturlaşdırmağa imkan verir:

    • 🔹 RemoteControl — abstraksiya təbəqəsi (istifadəçi interfeysi)
    • 🔸 AdvancedRemoteControl — genişləndirilmiş abstraksiya
    • 🔹 Device — implementasiya interfeysi
    • 🔸 TV, Radio — konkret implementasiyalar

    Bu struktur yeni cihazlar və ya uzaqdan idarəetmə növləri əlavə etdikdə kodun dəyişməsini minimuma endirir.


    ✅ Nəticə

    Bridge Pattern dizayn şablonu kompleks sistemlərdə asan genişləndirmə və idarəetmə üçün idealdır. JavaScript kimi obyekt yönümlü yanaşmanı dəstəkləyən dinamik dillərdə bu şablon real dünyada geniş istifadə olunur.

    Əgər siz komponentləriniz arasında zəif əlaqə (loose coupling) istəyirsinizsə, Bridge Pattern sizin üçün düzgün seçim ola bilər.

    Dizayn nümunələri design pattern bridge abstraction

  • Duck Typing nədir? JavaScript-də tətbiqi və nümunələrlə izah
    codexC codex

    Proqramlaşdırmada 🦆Duck Typing — tip yoxlamasının obyektin davranışına əsasən aparılması prinsipidir. Bu ifadə məşhur bir sitatdan götürülüb:

    “Əgər nəsə ördək kimi gəzir, ördək kimi səs çıxarırsa, deməli bu ördəkdir.”


    🧪 Duck Typing nə deməkdir?

    Duck Typing-də obyektin tipi yox, onun interfeysi və ya xüsusiyyətləri/metodları əsas götürülür. Yəni:

    function printName(entity) {
      if (typeof entity.sayName === "function") {
        entity.sayName();
      } else {
        console.log("Bu obyektin sayName funksiyası yoxdur.");
      }
    }
    

    Burada entity adlı obyektin sayName() funksiyası olub-olmaması yoxlanılır. Onun hansı sinifdən və ya hansı tipdən olması önəmli deyil. Bu, Duck Typing yanaşmasıdır.


    🛠 JavaScript-də Duck Typing nümunələri

    const user = {
      name: "Elvin",
      sayName() {
        console.log(`Mənim adım ${this.name}`);
      },
    };
    
    const robot = {
      id: 42,
      sayName() {
        console.log("Mən bir robotam.");
      },
    };
    
    function greet(entity) {
      entity.sayName(); // Duck Typing prinsipi
    }
    
    greet(user);   // Mənim adım Elvin
    greet(robot);  // Mən bir robotam.
    

    Hər iki obyektin sayName() funksiyası olduğu üçün greet() funksiyası uğurla işləyir. Obyektlərin tipi yox, davranışları ön plandadır.


    💡 Duck Typing ilə tip sistemi arasındakı fərqlər

    Xüsusiyyət Tip əsaslı yanaşma (OOP) Duck Typing (JavaScript)
    Tip yoxlanışı Kompilyasiya zamanı Run-time (işləmə zamanı)
    Tipə əsaslanma Sinif və interfeys Obyektin davranışı
    Quraşdırılmış tiplər Zəruridir Məcburi deyil
    Əsas məqsəd Güvənlik və sabitlik Çeviklik və sadəlik

    ⚠️ Duck Typing-in riskləri

    Duck Typing çox çevik olsa da, müəyyən risklər yarada bilər:

    • Run-time səhvlər: Əgər obyekt gözlənilən funksiyanı ehtiva etmirsə, proqram iş zamanı çökə bilər.
    • Oxunmaz kod: Tip təhlükəsizliyi olmadığından, böyük layihələrdə kodun izlənməsi çətinləşə bilər.
    • IDE köməyi az olur: Tip məlumatı olmadığı üçün kod tamamlaması və səhv yoxlamaları zəif ola bilər.

    Bu səbəblərə görə, TypeScript kimi dillər Duck Typing-in üstünlüklərini qoruyaraq, struktur tip yoxlaması (structural typing) təklif edir.


    ✅ Duck Typing vs Structural Typing (TypeScript)

    TypeScript-də interface vasitəsilə Duck Typing daha formal şəkildə tətbiq edilir:

    interface Nameable {
      sayName(): void;
    }
    
    function greet(entity: Nameable) {
      entity.sayName();
    }
    
    const person = {
      name: "Aysu",
      sayName() {
        console.log("Salam, mən Aysu");
      },
    };
    
    greet(person); // ✅ Keçərli: struktura uyğundur
    

    Burada person Nameable interfeysinə uyğun davranır, çünki sayName metoduna malikdir. Bu, TypeScript-də struktur əsaslı Duck Typing-dir.


    📌 Nəticə

    JavaScript-də Duck Typing proqramçıya obyektin funksionallığına görə davranmaq imkanı verir. Bu yanaşma, daha çevik və rahat kod yazmağa imkan yaratsa da, səhv ehtimallarını artırır. Böyük layihələrdə ya öz tip yoxlamanızı əlavə etməlisiniz, ya da TypeScript kimi həllərə üstünlük verməlisiniz.

    JavaScript types structural 🦆duck

  • 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
  • 1
  • 2
  • 3
  • 4
  • 1 / 4
  • 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