JavaScript'in En Yeni Veri Türüne İlişkin Temel Kılavuz: BigInt

Yayınlanan: 2022-03-10
Hızlı özet ↬ JavaScript'te, Number 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.

Atlamadan sonra daha fazlası! Aşağıdan okumaya devam edin ↓

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!