Sonlar

JavaScript'ning asosiy sonli tipi bo‘lgan Number tipi ham butun sonlarni ifodalash, ham haqiqiy sonlarni taqriban hisoblash uchun xizmat qiladi. JavaScript sonlarni ifodalash uchun IEEE 754 standarti1 bilan belgilangan 64 bitli suzuvchi nuqtali (floating-point) formatdan foydalanadi. Bu format ±1.7976931348623157 × 10³⁰⁸ gacha bo‘lgan ulkan va ±5 × 10⁻³²⁴ gacha bo‘lgan juda kichik sonlarni ifodalash imkonini beradi.

JavaScript'ning son formati −9,007,199,254,740,992 (−2⁵³) dan 9,007,199,254,740,992 (2⁵³) gacha bo‘lgan barcha butun sonlarni (shu sonlarning o‘zini ham qo‘shgan holda) mutlaqo aniq ifodalash imkonini beradi. Agar bundan katta butun sonlar bilan ishlasangiz, ularning oxirgi raqamlarida aniqlik yo‘qolishi mumkin. Shuni ta’kidlash joizki, JavaScript’dagi ba’zi amallar (masalan, massivlarni indekslash va 4-bobda yoritilgan bitli operatorlar) 32 bitli butun sonlar bilan bajariladi. Bundan ham katta butun sonlarni mutlaqo aniq ifodalash zarur bo‘lsa, §3.2.5-bo‘limga qarang.

JavaScript dasturi kodida to‘g‘ridan-to‘g‘ri yozilgan son sonli literal deb ataladi. JavaScript sonli literallarning bir necha formatini qo‘llab-quvvatlaydi va ular keyingi bo‘limlarda yoritilgan. Shuni ham aytib o‘tish kerakki, har qanday sonli literal oldidan minus (-) belgisi kelishi mumkin va bu uni manfiy songa aylantiradi.

Butun sonli literallar

JavaScript dasturida o‘nlik sanoq tizimidagi (base-10) butun son shunchaki raqamlar ketma-ketligi sifatida yoziladi. Masalan:

O‘nlik sanoq tizimidagi butun sonli literallardan tashqari, JavaScript o‘n oltilik (hexadecimal, base-16) qiymatlarni ham tushunadi. O‘n oltilik literal 0x yoki 0X bilan boshlanadi va undan keyin o‘n oltilik raqamlar ketma-ketligi keladi. O‘n oltilik raqam — bu 0 dan 9 gacha bo‘lgan raqamlardan biri yoki 10 dan 15 gacha bo‘lgan qiymatlarni ifodalovchi a (yoki A) dan f (yoki F) gacha bo‘lgan harflardir. Quyida o‘n oltilik butun sonli literallarga misollar keltirilgan:

ES6 va undan keyingi versiyalarda butun sonlarni 0x o‘rniga 0b va 0o (yoki 0B va 0O) prefikslari yordamida ikkilik (binary, base-2) yoki sakkizlik (octal, base-8) sanoq tizimlarida ham ifodalash mumkin:

Suzuvchi nuqtali literallar

Suzuvchi nuqtali literallar o‘nli kasr nuqtasiga ega bo‘lishi mumkin; ular haqiqiy sonlar uchun an’anaviy sintaksisdan foydalanadi. Haqiqiy qiymat sonning butun qismi, undan keyin keladigan o‘nli kasr nuqtasi va sonning kasr qismi sifatida ifodalanadi.

Suzuvchi nuqtali literallarni eksponensial yozuv yordamida ham ifodalash mumkin: bunda haqiqiy sondan keyin e (yoki E) harfi, undan keyin ixtiyoriy plyus yoki minus belgisi va undan keyin butun sonli daraja ko‘rsatkichi keladi. Bu yozuv haqiqiy sonni 10 ning ko‘rsatilgan darajasiga ko‘paytirishni anglatadi.

Qisqacha aytganda, sintaksis quyidagicha:

Sonli literallarda ajratuvchilar

Uzun literallarni o‘qish uchun qulayroq bo‘lgan qismlarga ajratish uchun sonli literallar ichida pastki chiziq (_) belgisidan foydalanishingiz mumkin:

Ushbu kitob yozilayotgan 2020-yil boshida sonli literallardagi pastki chiziqlar hali JavaScript'ning rasmiy standarti sifatida qabul qilinmagan edi. Biroq ular standartlashtirish jarayonining yuqori bosqichida turibdi va barcha asosiy brauzerlar hamda Node tomonidan implementatsiya qilingan.

JavaScript'da arifmetik amallar

JavaScript dasturlari til taqdim etadigan arifmetik operatorlar yordamida sonlar bilan ishlaydi. Bularga qo‘shish uchun +, ayirish uchun -, ko‘paytirish uchun *, bo‘lish uchun / va bo‘lgandagi qoldiqni topish uchun % (modulo) kiradi. ES2016 versiyasi darajaga ko‘tarissh uchun ** operatorini qo‘shgan. Bu va boshqa operatorlar haqidagi to‘liq ma’lumotni 4-bobdan topishingiz mumkin.

Ushbu asosiy arifmetik operatorlardan tashqari, JavaScript Math obyektining xossalari sifatida aniqlangan funksiyalar va konstantalar to‘plami orqali murakkabroq matematik amallarni ham qo‘llab-quvvatlaydi:

ES6 Math obyektiga yana qo‘shimcha funksiyalar kiritgan:

Cheksizlik va nolga bo‘lish

JavaScript'da arifmetik amallar xotiradan toshib ketish (overflow), minimal qiymatdan pasayib ketish (underflow) yoki nolga bo‘lish holatlarida xatolik yuzaga keltirmaydi. Sonli amal natijasi ifodalash mumkin bo‘lgan eng katta sondan oshib ketsa (overflow), natija maxsus cheksizlik qiymati — Infinity bo‘ladi. Xuddi shunday, manfiy qiymatning moduli ifodalash mumkin bo‘lgan eng katta manfiy sonning modulidan oshib ketsa, natija manfiy cheksizlik — -Infinity bo‘ladi.

Cheksiz qiymatlar o‘zini siz kutgandek tutadi: ularni biror narsaga qo‘shish, ayirish, ko‘paytirish yoki bo‘lish (ehtimol ishorasi o‘zgarishi bilan) yana cheksiz qiymatni beradi.

Underflow holati sonli amal natijasi ifodalash mumkin bo‘lgan eng kichik sondan ham nolga yaqinroq bo‘lganda yuz beradi. Bunday holda, JavaScript 0 qaytaradi. Agar underflow manfiy sondan kelib chiqsa, JavaScript "manfiy nol" deb nomlanuvchi maxsus qiymatni qaytaradi. Bu qiymat oddiy noldan deyarli farq qilmaydi va JavaScript dasturchilari uni aniqlashiga kamdan-kam ehtiyoj sezadilar.

Nolga bo‘lish JavaScript'da xatolik emas: u shunchaki Infinity yoki -Infinity qaytaradi. Biroq bitta istisno mavjud: nolni nolga bo‘lish aniq bir qiymatga ega emas va bu amalning natijasi maxsus "son emas" (not-a-number, son emas) qiymati — NaN bo‘ladi. NaN, shuningdek, cheksizlikni cheksizlikka bo‘lishga harakat qilganda, manfiy sondan kvadrat ildiz olganda yoki sonli bo‘lmagan va songa o‘girib bo‘lmaydigan operandlar bilan arifmetik operatorlarni ishlatganda ham paydo bo‘ladi.

JavaScript musbat cheksizlik va "son emas" qiymatlarini saqlash uchun global Infinity va NaN konstantalarini oldindan belgilab qo‘ygan. Bu qiymatlarga Number obyektining xossalari sifatida ham murojaat qilish mumkin:

NaN va manfiy nolning o‘ziga xosliklari

"Son emas" qiymatining JavaScript'da bitta g‘ayrioddiy xususiyati bor: u boshqa hech qanday qiymatga, jumladan, o‘ziga ham teng emas. Bu shuni anglatadiki, x o‘zgaruvchisining qiymati NaN ekanligini tekshirish uchun x === NaN deb yoza olmaysiz. Buning o‘rniga, x != x yoki Number.isNaN(x) deb yozishingiz kerak. Bu ifodalar faqat va faqat x global NaN konstantasi bilan bir xil qiymatga ega bo‘lgandagina true bo‘ladi.

Global isNaN() funksiyasi Number.isNaN()'ga o‘xshaydi. U argumenti NaN bo‘lsa yoki argument son bo‘lmagan va songa o‘girib bo‘lmaydigan qiymat bo‘lsa, true qaytaradi. Unga bog‘liq bo‘lgan Number.isFinite() funksiyasi esa argumenti NaN, Infinity yoki -Infinity'dan boshqa har qanday son bo‘lsa, true qaytaradi. Global isFinite() funksiyasi argumenti chekli son bo‘lsa yoki uni chekli songa o‘girishni imkoni bo‘lsa, true qaytaradi.

Manfiy nol qiymati ham biroz g‘ayrioddiydir. U musbat nolga (hatto JavaScript'ning qat’iy tenglik tekshiruvida ham) teng deb topiladi. Bu shuni anglatadiki, bu ikki qiymat bo‘luvchi sifatida ishlatilganidan tashqari deyarli farqlanmaydi:

Ikkilik suzuvchi nuqtali sonlar va yaxlitlash xatoliklari

Haqiqiy sonlar cheksiz ko‘p, lekin ularning faqat cheklangan miqdorigina (aniqrog‘i, 18,437,736,874,454,810,627 tasi) JavaScript'ning suzuvchi nuqtali formati orqali mutlaqo aniq ifodalanishi mumkin. Bu shuni anglatadiki, siz JavaScript'da haqiqiy sonlar bilan ishlayotganingizda, sonning ifodalanishi ko‘pincha haqiqiy sonning o‘ziga juda yaqin bo‘lgan taqribiy qiymat bo‘ladi.

JavaScript (va deyarli barcha boshqa zamonaviy dasturlash tillari) tomonidan qo‘llaniladigan IEEE-754 suzuvchi nuqtali ifodalash usuli ikkilik (binary) ifodalashdir. U 1/2, 1/8 va 1/1024 kabi kasrlarni mutlaqo aniq ifodalay oladi. Afsuski, biz eng ko‘p ishlatadigan kasrlar (ayniqsa, moliyaviy hisob-kitoblarda) o‘nli kasrlardir: 1/10, 1/100 va hokazo. Ikkilik suzuvchi nuqtali ifodalash usuli esa hatto 0.1 kabi oddiy sonni ham mutlaqo aniq ifodalay olmaydi.

JavaScript sonlari yetarlicha katta aniqlikka ega va 0.1 ni juda yaqin taqribiylikda ifodalay oladi. Ammo bu sonni mutlaqo aniq ifodalab bo‘lmasligi muammolarga olib kelishi mumkin. Quyidagi kodni ko‘rib chiqing:

Yaxlitlash xatoligi sababli, .3 va .2 ning taqribiy qiymatlari orasidagi farq, .2 va .1 ning taqribiy qiymatlari orasidagi farq bilan bir xil emas. Shuni tushunish muhimki, bu muammo faqat JavaScript'ga xos emas: u ikkilik suzuvchi nuqtali sonlardan foydalanadigan har qanday dasturlash tiliga ta’sir qiladi. Shuningdek, e’tibor bering, yuqoridagi kodda x va y qiymatlari bir-biriga va to‘g‘ri qiymatga juda yaqin. Hisoblangan bu qiymatlar deyarli har qanday maqsad uchun yetarlidir; muammo faqat qiymatlarni tenglikka tekshirishga harakat qilganimizda yuzaga keladi.

Agar bu kabi suzuvchi nuqtali taqribiyliklar dasturlaringizda muammo tug‘dirsa, masshtablangan butun sonlardan foydalanishni ko‘rib chiqing. Masalan, pul qiymatlari bilan ishlaganda, ularni kasrli dollar sifatida emas, balki butun sonli sentlar sifatida boshqarishingiz mumkin.

BigInt yordamida ixtiyoriy aniqlikdagi butun sonlar

JavaScript'ning ES2020'da kiritilgan eng yangi xususiyatlaridan biri bu BigInt deb nomlanuvchi yangi sonli tipdir. 2020-yil boshiga kelib, u Chrome, Firefox, Edge va Node'da implementatsiya qilingan, Safari'da esa implementatsiya jarayoni davom etmoqda. Nomidan ko‘rinib turganidek, BigInt — bu qiymatlari butun sonlardan iborat bo‘lgan sonli tip. Bu tip JavaScript'ga asosan boshqa ko‘plab dasturlash tillari va API'lar bilan moslik uchun talab etiladigan 64 bitli butun sonlarni ifodalash imkoniyatini berish uchun qo‘shilgan. Lekin agar sizga juda katta sonlar bilan ishlash kerak bo‘lsa, BigInt qiymatlari minglab, hatto millionlab raqamlarga ega bo‘lishi mumkin. (Biroq shuni yodda tutingki, BigInt implementatsiyalari kriptografiya uchun mos emas, chunki ular vaqtga bog‘liq hujumlarni (timing attacks) oldini olishga harakat qilmaydi.)

BigInt literallari raqamlar ketma-ketligi va undan keyin keladigan kichik n harfi bilan yoziladi. Standart holatda ular o‘nlik sanoq tizimida bo‘ladi, lekin ikkilik, sakkizlik va o‘n oltilik BigInt'lar uchun 0b, 0o va 0x prefikslaridan foydalanishingiz mumkin:

Siz BigInt() funksiyasidan oddiy JavaScript sonlari yoki satrlarini BigInt qiymatlariga o‘zgartirish uchun foydalanishingiz mumkin:

BigInt qiymatlari bilan arifmetik amallar oddiy JavaScript sonlari bilan ishlashga o‘xshaydi, faqat bo‘lish amali har qanday qoldiqni tashlab yuboradi va pastga qarab (nolga tomon) yaxlitlaydi:

Standart +, -, *, /, %va ** operatorlari BigInt bilan ishlasa-da, shuni tushunish muhimki, BigInt tipidagi operandlarni oddiy sonli operandlar bilan aralashtirib ishlata olmaysiz. Bu dastlab chalkash tuyulishi mumkin, lekin buning jiddiy sababi bor. Agar bir sonli tip boshqasidan umumiyroq bo‘lganida, aralash operandlar bilan arifmetikani shunchaki umumiyroq tipdagi qiymatni qaytaradigan qilib belgilash oson bo‘lardi. Lekin bu ikki tipdan hech biri boshqasidan umumiyroq emas: BigInt haddan ortiq katta qiymatlarni ifodalay oladi, bu uni oddiy sonlardan umumiyroq qiladi. Ammo BigInt faqat butun sonlarni ifodalay oladi, bu esa oddiy JavaScript son tipini umumiyroq qiladi. Bu muammoni hal qilishning iloji yo‘q, shuning uchun JavaScript arifmetik operatorlarga aralash operandlarni ishlatishga ruxsat bermaslik orqali bu muammoni chetlab o‘tadi.

Taqqoslash operatorlari esa, aksincha, aralash sonli tiplar bilan ishlay oladi (lekin == va === orasidagi farq haqida ko‘proq bilish uchun §3.9.1-bo‘limga qarang):

Bitli (Bitwise) operatorlar (§4.8.3-bo‘limda yoritilgan) odatda BigInt operandlari bilan ishlaydi. Biroq Math obyektining hech bir funksiyasi BigInt operandlarini qabul qilmaydi.

Sanalar va vaqtlar

JavaScript sanalar va vaqtlarni ifodalovchi sonlarni ko‘rsatish va ular ustida amallar bajarish uchun oddiy Date klassini taqdim etadi. JavaScript Date'lari obyektlardir, lekin ular bir vaqtning o‘zida 1970-yil, 1-yanvardan beri o‘tgan millisoniyalar sonini belgilovchi vaqt belgisiga (timestamp) — ya’ni, sonli ifodaga ham ega:

Date klassi va uning metodlari §11.4-bo‘limda batafsil yoritilgan. Lekin biz Date obyektlarini JavaScript tiplarini o‘zgartirish tafsilotlarini ko‘rib chiqayotganimizda, §3.9.3-bo‘limda yana bir bor uchratamiz.

  1. Bu Java, C++ va ko‘pchilik zamonaviy dasturlash tillaridagi double tipidagi sonlar uchun qo‘llaniladigan formatdir.