JavaScript'in En Yeni Veri Türüne İlişkin Temel Kılavuz: BigInt
Yayınlanan: 2022-03-10Number
türü 2'den büyük tamsayı değerlerini güvenli bir şekilde gösteremez 53 . Bu sınırlama, geliştiricileri verimsiz geçici çözümler ve üçüncü taraf kitaplıkları kullanmaya zorladı. BigInt
, bunu düzeltmeyi amaçlayan yeni bir veri türüdür. BigInt
veri türü, JavaScript programcılarının Number
veri türü tarafından desteklenen aralıktan daha büyük tamsayı değerlerini temsil etmesini sağlamayı amaçlar. Tamsayıları keyfi hassasiyetle temsil etme yeteneği, büyük tamsayılar üzerinde matematiksel işlemler gerçekleştirirken özellikle önemlidir. BigInt
ile tamsayı taşması artık sorun olmayacak.
Ayrıca, bir geçici çözüm kullanmak zorunda kalmadan yüksek çözünürlüklü zaman damgaları, büyük tamsayı kimlikleri ve daha fazlasıyla güvenle çalışabilirsiniz. BigInt
şu anda bir 3. aşama önerisidir. Spesifikasyona eklendiğinde, JavaScript'teki ikinci sayısal veri türü olacak ve bu da desteklenen veri türlerinin toplam sayısını sekize çıkaracak:
- Boole
- Boş
- Tanımsız
- Numara
- BigInt
- Sicim
- sembol
- Nesne
Bu makalede, BigInt
iyi bir göz atacağız ve JavaScript'teki Number
türünün sınırlamalarının üstesinden nasıl gelebileceğini göreceğiz.
Sorun
JavaScript'te açık bir tamsayı türünün olmaması, diğer dillerden gelen programcılar için genellikle şaşırtıcıdır. Birçok programlama dili, kayan nokta, çift, tamsayı ve büyük sayı gibi birden çok sayısal türü destekler, ancak JavaScript'te durum böyle değildir. JavaScript'te tüm sayılar, IEEE 754-2008 standardı tarafından tanımlandığı gibi çift duyarlıklı 64 bit kayan nokta biçiminde temsil edilir.
Bu standarda göre, tam olarak temsil edilemeyen çok büyük tamsayılar otomatik olarak yuvarlanır. Kesin olmak gerekirse, JavaScript'teki Number
türü yalnızca -9007199254740991 (-(2 53 -1)) ile 9007199254740991 (2 53 -1) arasındaki tam sayıları güvenli bir şekilde temsil edebilir. Bu aralığın dışında kalan herhangi bir tamsayı değeri kesinliğini kaybedebilir.
Bu, aşağıdaki kodu çalıştırarak kolayca incelenebilir:
console.log(9999999999999999); // → 10000000000000000
Bu tam sayı, JavaScript'in ilkel Number
ile güvenilir şekilde temsil edebileceği en büyük sayıdan daha büyüktür. Bu nedenle yuvarlaktır. Beklenmeyen yuvarlama, bir programın güvenilirliğini ve güvenliğini tehlikeye atabilir. İşte başka bir örnek:
// notice the last digits 9007199254740992 === 9007199254740993; // → true
JavaScript, JavaScript'te maksimum güvenli tamsayıyı hızla elde etmenizi sağlayan Number.MAX_SAFE_INTEGER
sabitini sağlar. Benzer şekilde, Number.MIN_SAFE_INTEGER
sabitini kullanarak minimum güvenli tamsayıyı elde edebilirsiniz:
const minInt = Number.MIN_SAFE_INTEGER; console.log(minInt); // → -9007199254740991 console.log(minInt - 5); // → -9007199254740996 // notice how this outputs the same value as above console.log(minInt - 4); // → -9007199254740996
Çözüm
Bu sınırlamalara geçici bir çözüm olarak, bazı JavaScript geliştiricileri, String
türünü kullanarak büyük tamsayıları temsil eder. Örneğin Twitter API, JSON ile yanıt verirken nesnelere kimliklerin bir dize sürümünü ekler. Ek olarak, büyük tamsayılarla çalışmayı kolaylaştırmak için bignumber.js gibi bir dizi kitaplık geliştirilmiştir.
BigInt
ile uygulamaların artık Number.MAX_SAFE_INTEGER
ve Number.Min_SAFE_INTEGER
dışındaki tam sayıları güvenli bir şekilde temsil etmek için bir geçici çözüme veya kitaplığa ihtiyacı yoktur. Büyük tamsayılar üzerindeki aritmetik işlemler artık standart JavaScript'te hassasiyet kaybı riski olmadan gerçekleştirilebilir. Üçüncü taraf kitaplığı üzerinden yerel bir veri türü kullanmanın ek avantajı, daha iyi çalışma zamanı performansıdır.
Bir BigInt
oluşturmak için bir tamsayının sonuna n
eklemeniz yeterlidir. Karşılaştırmak:
console.log(9007199254740995n); // → 9007199254740995n console.log(9007199254740995); // → 9007199254740996
Alternatif olarak, BigInt()
yapıcısını çağırabilirsiniz:
BigInt("9007199254740995"); // → 9007199254740995n
BigInt
değişmez değerleri ikili, sekizli veya onaltılı gösterimde de yazılabilir:
// binary console.log(0b100000000000000000000000000000000000000000000000000011n); // → 9007199254740995n // hex console.log(0x20000000000003n); // → 9007199254740995n // octal console.log(0o400000000000000003n); // → 9007199254740995n // note that legacy octal syntax is not supported console.log(0400000000000000003n); // → SyntaxError
Aynı türden olmadıkları için bir BigInt
normal bir sayıyla karşılaştırmak için katı eşitlik operatörünü kullanamayacağınızı unutmayın:
console.log(10n === 10); // → false console.log(typeof 10n); // → bigint console.log(typeof 10); // → number
Bunun yerine, işlenenlerini karşılaştırmadan önce örtük tür dönüşümü gerçekleştiren eşitlik operatörünü kullanabilirsiniz:
console.log(10n == 10); // → true
Tekli artı ( +
) operatörü dışında tüm aritmetik operatörler BigInt
kullanılabilir:
10n + 20n; // → 30n 10n - 20n; // → -10n +10n; // → TypeError: Cannot convert a BigInt value to a number -10n; // → -10n 10n * 20n; // → 200n 20n / 10n; // → 2n 23n % 10n; // → 3n 10n ** 3n; // → 1000n let x = 10n; ++x; // → 11n --x; // → 10n
unary plus ( +
) operatörünün desteklenmemesinin nedeni, bazı programların +
her zaman bir Number
üreten veya bir istisna oluşturan değişmeze güvenebilmesidir. +
davranışının değiştirilmesi asm.js kodunu da bozar.
Doğal olarak, BigInt
işlenenleriyle birlikte kullanıldığında, aritmetik operatörlerin bir BigInt
değeri döndürmesi beklenir. Bu nedenle, bölme ( /
) operatörünün sonucu otomatik olarak kesilir. Örneğin:
25 / 10; // → 2.5 25n / 10n; // → 2n
Örtülü Tür Dönüşümü
Örtülü tür dönüştürme bilgileri kaybedebileceğinden, BigInt
s ve Number
s arasında karışık işlemlere izin verilmez. Büyük tam sayıları ve kayan noktalı sayıları karıştırırken, elde edilen değer BigInt
veya Number
ile doğru şekilde temsil edilemeyebilir. Aşağıdaki örneği göz önünde bulundurun:
(9007199254740992n + 1n) + 0.5
Bu ifadenin sonucu hem BigInt
hem de Number
alanının dışındadır. Kesirli kısmı olan bir Number
, doğru bir şekilde BigInt
dönüştürülemez. Ve 2 53'ten büyük bir BigInt
, doğru bir şekilde Number
dönüştürülemez.
Bu kısıtlamanın bir sonucu olarak, Number
ve BigInt
işlenenlerinin karışımıyla aritmetik işlemler yapmak mümkün değildir. Ayrıca bir BigInt
Web API'lerine ve Number
bekleyen yerleşik JavaScript işlevlerine iletemezsiniz. Bunu yapmaya çalışmak TypeError
neden olur:
10 + 10n; // → TypeError Math.max(2n, 4n, 6n); // → TypeError
Bu örnekte gösterildiği gibi, ilişkisel işleçlerin bu kuralı takip etmediğini unutmayın:
10n > 5; // → true
BigInt
ve Number
ile aritmetik hesaplamalar yapmak istiyorsanız öncelikle işlemin yapılacağı domaini belirlemelisiniz. Bunu yapmak için, Number()
veya BigInt()
çağırarak işlenenlerden birini dönüştürmeniz yeterlidir:
BigInt(10) + 10n; // → 20n // or 10 + Number(10n); // → 20
Boolean
bağlamında karşılaşıldığında, BigInt
, Number
ile benzer şekilde ele alınır. Başka bir deyişle, bir BigInt
, 0n
olmadığı sürece doğru bir değer olarak kabul edilir:
if (5n) { // this code block will be executed } if (0n) { // but this code block won't }
Bir dizi BigInt
ve Number
türleri arasında örtük tür dönüşümü gerçekleşmez:
const arr = [3n, 4, 2, 1n, 0, -1n]; arr.sort(); // → [-1n, 0, 1n, 2, 3n, 4]
Bitsel operatörler, örneğin |
, &
, <<
, >>
, ve ^
BigInt
s üzerinde Number
s'ye benzer şekilde çalışır. Negatif sayılar sonsuz uzunlukta ikinin tümleyeni olarak yorumlanır. Karışık işlenenlere izin verilmez. İşte bazı örnekler:
90 | 115; // → 123 90n | 115n; // → 123n 90n | 115; // → TypeError
BigInt Oluşturucu
Diğer ilkel türlerde olduğu gibi, bir yapıcı işlevi kullanılarak bir BigInt
oluşturulabilir. BigInt()
öğesine iletilen bağımsız değişken, mümkünse otomatik olarak bir BigInt
öğesine dönüştürülür:
BigInt("10"); // → 10n BigInt(10); // → 10n BigInt(true); // → 1n
Dönüştürülemeyen veri türleri ve değerler bir istisna atar:
BigInt(10.2); // → RangeError BigInt(null); // → TypeError BigInt("abc"); // → SyntaxError
Bir yapıcı kullanılarak oluşturulan bir BigInt
üzerinde doğrudan aritmetik işlemler gerçekleştirebilirsiniz:
BigInt(10) * 10n; // → 100n
Kesin eşitlik operatörünün işlenenleri olarak kullanıldığında, bir kurucu kullanılarak oluşturulan BigInt
'ler normal olanlara benzer şekilde ele alınır:
BigInt(true) === 1n; // → true
Kütüphane Fonksiyonları
JavaScript, BigInt
değerlerini işaretli veya işaretsiz tamsayılar olarak temsil etmek için iki kitaplık işlevi sağlar:
-
BigInt.asUintN(width, BigInt)
BigInt
Bir BigInt'i 0 ile 2 genişlik -1 arasında sarar -
BigInt.asIntN(width, BigInt)
BigInt
bir BigInt'i -2 genişlik-1 ve 2 genişlik-1 -1 arasında sarar
Bu işlevler özellikle 64-bit aritmetik işlemler gerçekleştirirken kullanışlıdır. Bu şekilde istenilen aralıkta kalabilirsiniz.
Tarayıcı Desteği ve Aktarma
Bu yazının yazıldığı sırada Chrome +67 ve Opera +54, BigInt
veri türünü tam olarak desteklemektedir. Ne yazık ki, Edge ve Safari henüz uygulamadı. Firefox varsayılan olarak BigInt
desteklemez, ancak about:config
içinde javascript.options.bigint
true
olarak ayarlanarak etkinleştirilebilir. Desteklenen tarayıcıların güncel bir listesi Can I use…'da mevcuttur.
Ne yazık ki, BigInt
aktarmak son derece karmaşık bir süreçtir ve ağır çalışma zamanı performans cezasına neden olur. Teklif, mevcut birkaç operatörün davranışını değiştirdiği için BigInt
doğrudan çoklu doldurmak da imkansızdır. Şimdilik, BigInt
teklifinin salt JavaScript uygulaması olan JSBI kitaplığını kullanmak daha iyi bir alternatiftir.
Bu kitaplık, yerel BigInt
ile tamamen aynı şekilde davranan bir API sağlar. JSBI'yi şu şekilde kullanabilirsiniz:
import JSBI from './jsbi.mjs'; const b1 = JSBI.BigInt(Number.MAX_SAFE_INTEGER); const b2 = JSBI.BigInt('10'); const result = JSBI.add(b1, b2); console.log(String(result)); // → '9007199254741001'
JSBI kullanmanın bir avantajı, tarayıcı desteği iyileştiğinde kodunuzu yeniden yazmanıza gerek kalmamasıdır. Bunun yerine, bir babel eklentisi kullanarak JSBI kodunuzu yerel BigInt
koduna otomatik olarak derleyebilirsiniz. Ayrıca, JSBI'nin performansı, yerel BigInt
uygulamalarıyla eşittir. Yakında BigInt
için daha geniş tarayıcı desteği bekleyebilirsiniz.
Çözüm
BigInt
, tamsayı değerleri Number
veri türü tarafından desteklenen aralıktan daha büyük olduğunda kullanılması amaçlanan yeni bir veri türüdür. Bu veri türü, büyük tamsayılar üzerinde güvenli bir şekilde aritmetik işlemler gerçekleştirmemize, yüksek çözünürlüklü zaman damgalarını temsil etmemize, büyük tamsayı kimlikleri kullanmamıza ve daha fazlasını bir kitaplık kullanmaya gerek kalmadan yapmamıza olanak tanır.
Number
ve BigInt
işlenenlerinin bir karışımıyla aritmetik işlemler gerçekleştiremeyeceğinizi unutmamak önemlidir. İşlenenlerden herhangi birini açıkça dönüştürerek işlemin yapılması gereken etki alanını belirlemeniz gerekir. Ayrıca, uyumluluk nedenleriyle, bir BigInt
üzerinde unary plus ( +
) operatörünü kullanmanıza izin verilmez.
Ne düşünüyorsun? BigInt
faydalı buluyor musunuz? Yorumlarda bize bildirin!