25 август 2025

Statik xususiyatlar va usullar

Shuningdek, biz usulni "prototype" ga emas, balki klassning funktsiyasiga tayinlashimiz mumkin. Bunday usullar statik deb nomlanadi.

Misol:

class User {
  static staticMethod() {
    alert(this === User);
  }
}

User.staticMethod(); // true

Bu aslida uni funktsiya xususiyati sifatida tayinlash bilan bir xil bo’ladi:

class User {}

User.staticMethod = function () {
  alert(this === User);
};

User.staticMethod(); // true

User.staticMethod() ichidagi this qiymati User klass konstruktoridir (“nuqta oldidagi obyekt” qoidasi).

Odatda, statik usullar klassga tegishli funktsiyalarni amalga oshirish uchun ishlatiladi, lekin uning biron bir alohida obyektiga emas.

Masalan, bizda Article obyektlari mavjud va ularni taqqoslash funktsiyasi zarur. Tabiiy tanlov quyidagicha Article.compare bo’ladi:

class Article {
  constructor(title, date) {
    this.title = title;
    this.date = date;
  }

  static compare(articleA, articleB) {
    return articleA.date - articleB.date;
  }
}

// usage
let articles = [
  new Article("HTML", new Date(2019, 1, 1)),
  new Article("CSS", new Date(2019, 0, 1)),
  new Article("JavaScript", new Date(2019, 11, 1))
];

articles.sort(Article.compare);

alert( articles[0].title ); // CSS

Bu yerda Article.compare maqolalarni “ustidan” taqqoslash vositasi sifatida turadi. Bu maqola usuli uchun emas, balki butun klass uchun.

Yana bir misol “fabrika” deb nomlangan usul bo’lishi mumkin. Tasavvur qiling, bizga maqola yaratishning bir necha yo’li bor:

  1. Berilgan parametrlar bo’yicha yaratish (title, date va hokazo).
  2. Bugungi sana bilan bo’sh maqola yarating.
  3. …yoki yana nimadir.

Birinchi usul konstruktor tomonidan amalga oshirilishi mumkin. Va ikkinchisi uchun biz klassning statik usulini yaratishimiz mumkin.

Article.createTodays() singari bu yerda:

class Article {
  constructor(title, date) {
    this.title = title;
    this.date = date;
  }

  static createTodays() {
    // eslab qoling, this = Article
    return new this("Bugungi dayjest", new Date());
  }
}

let article = Article.createTodays();

alert( article.title ); // Bugungi dayjest

Endi har safar bugungi dayjestni yaratishimiz kerak bo’lsa, biz Article.createTodays() deb chaqirishimiz mumkin. Yana bir bor takrorlayman, bu maqola usuli emas, balki butun klassning usuli.

Ma’lumotlar bazasi bilan bog’liq klasslarda statik usullar ma’lumotlar bazasidan yozuvlarni qidirish/saqlash/olib tashlash uchun quyidagi kabi qo’llaniladi:

// Article - maqolalarni boshqarish uchun maxsus klass deb taxmin qilamiz
// maqolani olib tashlash uchun statik usul:
Article.remove({ id: 12345 });

Statik xususiyatlar

Yaqinda qo'shilgan
Bu tilga yaqinda qo'shilgan narsa. Misollar yangi Chrome-da ishlaydi .

Statik xususiyatlar, odatdagi klass xususiyatlari singari ham mumkin:

class Article {
  static publisher = "Oybek Zokhidov";
}

alert(Article.publisher); // Oybek Zokhidov

Bu Article ga to’g’ridan-to’g’ri tayinlash bilan bir xil

Article.publisher = "Oybek Zokhidov";

Statika va meros

Statika bu meros, biz Parent.method ga Child.metho" sifatida kirishimiz mumkin.

Masalan, quyidagi koddagi Animal.compare meros qilib olingan va Rabbit.compare sifatida undan foydalanish mumkin:

class Animal {
  static planet = "Earth";

  constructor(name, speed) {
    this.speed = speed;
    this.name = name;
  }

  run(speed = 0) {
    this.speed += speed;
    alert(`${this.name} ${this.speed} tezlikda yuguradi.`);
  }

  static compare(animalA, animalB) {
    return animalA.speed - animalB.speed;
  }

}

// Animal-dan meros
class Rabbit extends Animal {
  hide() {
    alert(`${this.name} bekinadi!`);
  }
}

let rabbits = [
  new Rabbit("White Rabbit", 10),
  new Rabbit("Black Rabbit", 5)
];

rabbits.sort(Rabbit.compare);

rabbits[0].run(); // Black Rabbit 5 tezlikda yuguradi.

Endi biz Rabbit.compare ni meros qilib olingan Animal.compare chaqiriladi taxmin qilishimiz mumkin.

Bu qanday ishlaydi? Shunga qaramay, prototiplardan foydalanish. Siz allaqachon taxmin qilganingizdek, kengaytmalar Rabbit ga [[Prototype]] ning havolasini Animal ga beradi.

Shunday qilib, Rabbit funktsiyasi endi Animal funktsiyasini egallaydi. Va Animal funktsiyasi odatda Function.prototype ga tegishli [[Prototype]] ga ega, chunki u hech narsani kengaytirmaydi.

Mana, buni tekshirib ko’raylik:

class Animal {}
class Rabbit extends Animal {}

// statik xususiyatlar va usullar uchun
alert(Rabbit.__proto__ === Animal); // true

// va keyingi qadam - bu Function.prototype
alert(Animal.__proto__ === Function.prototype); // true

// bu obyekt usullari uchun "oddiy" prototip zanjiriga qo'shimcha ravishda
alert(Rabbit.prototype.__proto__ === Animal.prototype);

Shunday qilib, Rabbit Animal ning barcha statik usullaridan foydalanish imkoniyatiga ega.

Xulosa

Statik usullar aniq klass misoli bilan bog’liq bo’lmagan, misol uchun mavjud bo’lishni talab qilmaydigan, aksincha Article.compare singari umuman klassga tegishli bo’lgan funksiyalar uchun ishlatiladi – taqqoslash uchun umumiy usul ikkita maqola.

Statik xususiyatlar, masalan, misol bilan bog’liq bo’lmagan, klass darajasidagi ma’lumotlarni saqlashni xohlaganimizda ishlatiladi.

Sintaksis:

class MyClass {
  static property = ...;

  static method() {
    ...
  }
}

Bu texnik jihatdan klassning o’ziga tayinlash bilan bir xil:

MyClass.property = ...
MyClass.method = ...

Statik xususiyatlar meros qilib olinadi.

Texnik, uchun class B extends A klass prototipi B o’zi A ishora uzaytiradi: B.[[Prototype]] = A. Demak, B da biror maydon topilmasa, qidiruv A da davom etadi.

Vazifalar

Ma’lumki, barcha obyektlar odatda Object.prototype dan meros bo’lib, hasOwnProperty va boshqalar kabi “umumiy” obyekt usullariga kirish huquqiga ega.

Masalan:

class Rabbit {
  constructor(name) {
    this.name = name;
  }
}

let rabbit = new Rabbit("Rab");

// hasOwnProperty method is from Object.prototype
alert( rabbit.hasOwnProperty('name') ); // true

Agar biz uni "class Rabbit extends Object" kabi aniq yozsak, natija oddiy "class Rabbit" dan farq qiladimi?

Farqi nima?

Mana bunday kodning misoli (u ishlamaydi – nima uchun? uni tuzating):

class Rabbit extends Object {
  constructor(name) {
    this.name = name;
  }
}

let rabbit = new Rabbit("Rab");

alert(rabbit.hasOwnProperty("name")); // Error

Birinchidan, nima uchun oxirgi kod ishlamasligini ko’rib chiqamiz.

Agar biz uni ishlatishga harakat qilsak, sabab aniq bo’ladi. Meros klass konstruktori super() ni chaqirishi kerak. Aks holda "this" “aniqlanmaydi”.

Shunday qilib, tuzatish:

class Rabbit extends Object {
  constructor(name) {
    super(); // meros olishda ota konstruktorni chaqirish kerak
    this.name = name;
  }
}

let rabbit = new Rabbit("Rab");

alert( rabbit.hasOwnProperty('name') ); // true

Ammo bu hali hammasi emas.

Tuzatishdan keyin ham, "class Rabbit extends Object" va class Rabbit o’rtasida hali ham muhim farq bor.

Ma’lumki, “kengaytirish” sintaksisida ikkita prototip mavjud:

  1. Konstruktor funktsiyalarining "prototype" o’rtasida (usullar uchun).
  2. Konstruktor funktsiyalari orasida (statik usullar uchun).

Bizning holatimizda, class Rabbit extends Object uchun bu quyidagilarni anglatadi:

class Rabbit extends Object {}

alert(Rabbit.prototype.__proto__ === Object.prototype); // (1) true
alert(Rabbit.__proto__ === Object); // (2) true

Shunday qilib, Rabbit endi Rabbit orqali Object ning statik usullariga kirishni ta’minlaydi:

class Rabbit extends Object {}

// odatda bizchaqiramiz Object.getOwnPropertyNames
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // a,b

Agar bizda extends Object bo’lmasa, Rabbit.__ proto__ Object ga o’rnatilmagan.

Mana demo:

class Rabbit {}

alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) false (!)
alert( Rabbit.__proto__ === Function.prototype ); // sukut bo'yicha har qanday funktsiya sifatida

// xato, Rabbit-da bunday funktsiya yo'q
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error

Shunday qilib, Rabbit bu holda Object ning statik usullariga kirishni ta’minlamaydi.

Aytgancha, Function.prototype “umumiy” funktsiya usullariga ega, masalan call, bind va boshqalar. Ikkala holatda ham ular mavjud, chunki Object konstruktori Object.__ proto__ = == Funktsiya.prototype.

Here’s the picture:

Shunday qilib, qisqacha aytganda, ikkita farq bor:

class Rabbit class Rabbit extends Object
konstruktorda super() ni chaqirish kerak
Rabbit.__proto__ === Function.prototype Rabbit.__proto__ === Object
O'quv qo'llanma xaritasi

Izohlar

izoh berishdan oldin buni o'qing…
  • Agar sizda nimani yaxshilash kerakligi haqida takliflaringiz bo'lsa - iltimos, GitHub muammosini yuboring yoki izoh berish o'rniga so'rov yuboring.
  • Agar siz maqolada biror narsani tushunolmasangiz - iltimos, batafsilroq ma'lumot bering.
  • Bir nechta so'z so'zlarini kiritish uchun <code> yorlig'ini ishlating, bir nechta satrlar uchun - ularni <pre> yorlig'i bilan o'rab qo'ying, 10 satrdan ortiq bo'lsa - sandbox (plnkr, jsbin, codepen…)