JavaScript의 최신 데이터 유형에 대한 필수 가이드: BigInt
게시 됨: 2022-03-10Number
유형은 2 53 보다 큰 정수 값을 안전하게 표현할 수 없습니다. 이 제한으로 인해 개발자는 비효율적인 해결 방법과 타사 라이브러리를 사용해야 했습니다. BigInt
는 이를 수정하기 위한 새로운 데이터 유형입니다. BigInt
데이터 유형은 JavaScript 프로그래머가 Number
데이터 유형이 지원하는 범위보다 큰 정수 값을 나타낼 수 있도록 하는 것을 목표로 합니다. 임의의 정밀도로 정수를 나타내는 기능은 큰 정수에 대해 수학 연산을 수행할 때 특히 중요합니다. BigInt
를 사용하면 정수 오버플로가 더 이상 문제가 되지 않습니다.
또한 해결 방법을 사용하지 않고도 고해상도 타임스탬프, 큰 정수 ID 등으로 안전하게 작업할 수 있습니다. BigInt
는 현재 3단계 제안입니다. 사양에 추가되면 JavaScript에서 두 번째 숫자 데이터 유형이 되어 지원되는 총 데이터 유형 수가 8개가 됩니다.
- 부울
- 없는
- 한정되지 않은
- 숫자
- BigInt
- 끈
- 상징
- 물체
이 기사에서는 BigInt
를 잘 살펴보고 JavaScript에서 Number
유형의 한계를 극복하는 데 어떻게 도움이 되는지 알아보겠습니다.
문제
JavaScript에 명시적 정수 유형이 없다는 것은 다른 언어에서 온 프로그래머에게 종종 당혹스럽습니다. 많은 프로그래밍 언어는 float, double, integer 및 bignum과 같은 여러 숫자 유형을 지원하지만 JavaScript에서는 그렇지 않습니다. JavaScript에서 모든 숫자는 IEEE 754-2008 표준에 정의된 배정밀도 64비트 부동 소수점 형식으로 표시됩니다.
이 표준에서는 정확하게 표현할 수 없는 매우 큰 정수는 자동으로 반올림됩니다. 정확히 말하면 JavaScript의 Number
유형은 -9007199254740991(-(2 53 -1))에서 9007199254740991(2 53 -1) 사이의 정수만 안전하게 표현할 수 있습니다. 이 범위를 벗어나는 모든 정수 값은 정밀도를 잃을 수 있습니다.
이것은 다음 코드를 실행하여 쉽게 확인할 수 있습니다.
console.log(9999999999999999); // → 10000000000000000
이 정수는 JavaScript가 Number
프리미티브로 안정적으로 나타낼 수 있는 가장 큰 수보다 큽니다. 따라서 둥근 모양입니다. 예상치 못한 반올림은 프로그램의 안정성과 보안을 손상시킬 수 있습니다. 다음은 또 다른 예입니다.
// notice the last digits 9007199254740992 === 9007199254740993; // → true
JavaScript는 JavaScript에서 최대 안전한 정수를 빠르게 얻을 수 있는 Number.MAX_SAFE_INTEGER
상수를 제공합니다. 마찬가지로 Number.MIN_SAFE_INTEGER
상수를 사용하여 최소 안전 정수를 얻을 수 있습니다.
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
해결책
이러한 제한 사항을 해결하기 위해 일부 JavaScript 개발자는 String
유형을 사용하여 큰 정수를 나타냅니다. 예를 들어 Twitter API는 JSON으로 응답할 때 개체에 ID의 문자열 버전을 추가합니다. 또한 bignumber.js와 같은 많은 라이브러리가 큰 정수 작업을 더 쉽게 하기 위해 개발되었습니다.
BigInt
를 사용하면 애플리케이션에서 더 이상 Number.MAX_SAFE_INTEGER
및 Number.Min_SAFE_INTEGER
이상의 정수를 안전하게 나타내기 위한 해결 방법이나 라이브러리가 필요하지 않습니다. 큰 정수에 대한 산술 연산은 이제 정밀도 손실 위험 없이 표준 JavaScript에서 수행할 수 있습니다. 타사 라이브러리보다 기본 데이터 유형을 사용하면 런타임 성능이 향상된다는 추가 이점이 있습니다.
BigInt
를 생성하려면 정수 끝에 n
을 추가하기만 하면 됩니다. 비교하다:
console.log(9007199254740995n); // → 9007199254740995n console.log(9007199254740995); // → 9007199254740996
또는 BigInt()
생성자를 호출할 수 있습니다.
BigInt("9007199254740995"); // → 9007199254740995n
BigInt
리터럴은 2진법, 8진법 또는 16진법 표기법으로도 작성할 수 있습니다.
// 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
BigInt는 동일한 유형이 아니기 때문에 BigInt
를 일반 숫자와 비교할 때 완전 항등 연산자를 사용할 수 없습니다.
console.log(10n === 10); // → false console.log(typeof 10n); // → bigint console.log(typeof 10); // → number
대신 피연산자를 비교하기 전에 암시적 유형 변환을 수행하는 등호 연산자를 사용할 수 있습니다.
console.log(10n == 10); // → true
단항 더하기( +
) 연산자를 제외한 모든 산술 연산자는 BigInt
에서 사용할 수 있습니다.
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
단항 더하기( +
) 연산자가 지원되지 않는 이유는 일부 프로그램이 +
가 항상 Number
를 생성하거나 예외를 발생시키는 불변에 의존할 수 있기 때문입니다. +
의 동작을 변경하면 asm.js 코드도 손상됩니다.
당연히 BigInt
피연산자와 함께 사용되는 경우 산술 연산자는 BigInt
값을 반환해야 합니다. 따라서 나누기( /
) 연산자의 결과는 자동으로 잘립니다. 예를 들어:
25 / 10; // → 2.5 25n / 10n; // → 2n
암시적 유형 변환
암시적 형식 변환은 정보를 잃을 수 있기 때문에 BigInt
와 Number
사이의 혼합 작업은 허용되지 않습니다. 큰 정수와 부동 소수점 숫자를 혼합하면 결과 값이 BigInt
또는 Number
로 정확하게 표현되지 않을 수 있습니다. 다음 예를 고려하십시오.
(9007199254740992n + 1n) + 0.5
이 표현식의 결과는 BigInt
및 Number
도메인 외부에 있습니다. 소수 부분이 있는 Number
는 BigInt
로 정확하게 변환될 수 없습니다. 그리고 2 53 보다 큰 BigInt
는 정확하게 Number
로 변환될 수 없습니다.
이 제한 사항으로 인해 Number
및 BigInt
피연산자를 혼합하여 산술 연산을 수행할 수 없습니다. 또한 Number
가 필요한 Web API 및 내장 JavaScript 함수에 BigInt
를 전달할 수 없습니다. 그렇게 하려고 하면 TypeError
가 발생합니다.
10 + 10n; // → TypeError Math.max(2n, 4n, 6n); // → TypeError
관계 연산자는 다음 예와 같이 이 규칙을 따르지 않습니다.
10n > 5; // → true
BigInt
및 Number
를 사용하여 산술 계산을 수행하려면 먼저 작업이 수행되어야 하는 도메인을 결정해야 합니다. 그렇게 하려면 Number()
또는 BigInt()
를 호출하여 피연산자 중 하나를 변환하기만 하면 됩니다.
BigInt(10) + 10n; // → 20n // or 10 + Number(10n); // → 20
Boolean
컨텍스트에서 발생하면 BigInt
는 Number
와 유사하게 처리됩니다. 즉, BigInt
는 0n
이 아닌 한 진실 값으로 간주됩니다.
if (5n) { // this code block will be executed } if (0n) { // but this code block won't }
배열을 정렬할 때 BigInt
와 Number
유형 간의 암시적 유형 변환이 발생하지 않습니다.
const arr = [3n, 4, 2, 1n, 0, -1n]; arr.sort(); // → [-1n, 0, 1n, 2, 3n, 4]
|
와 같은 비트 연산자 , &
, <<
, >>
및 ^
는 BigInt
에서 Number
와 유사한 방식으로 작동합니다. 음수는 무한 길이의 2의 보수로 해석됩니다. 혼합 피연산자는 허용되지 않습니다. 여기 예시들이 있습니다 :
90 | 115; // → 123 90n | 115n; // → 123n 90n | 115; // → TypeError
BigInt 생성자
다른 기본 유형과 마찬가지로 BigInt
는 생성자 함수를 사용하여 생성할 수 있습니다. BigInt()
에 전달된 인수는 가능한 경우 BigInt
로 자동 변환됩니다.
BigInt("10"); // → 10n BigInt(10); // → 10n BigInt(true); // → 1n
변환할 수 없는 데이터 유형 및 값은 예외를 throw합니다.
BigInt(10.2); // → RangeError BigInt(null); // → TypeError BigInt("abc"); // → SyntaxError
생성자를 사용하여 생성된 BigInt
에 대해 산술 연산을 직접 수행할 수 있습니다.
BigInt(10) * 10n; // → 100n
완전 항등 연산자의 피연산자로 사용되는 경우 생성자를 사용하여 생성된 BigInt
는 일반 것과 유사하게 처리됩니다.
BigInt(true) === 1n; // → true
라이브러리 기능
JavaScript는 BigInt
값을 부호 있는 정수 또는 부호 없는 정수로 나타내기 위한 두 가지 라이브러리 함수를 제공합니다.
-
BigInt.asUintN(width, BigInt)
: 0과 2 너비 -1 사이에서BigInt
를 래핑합니다. -
BigInt.asIntN(width, BigInt)
: -2 너비 -1과 2 너비 -1 -1 사이에서BigInt
를 래핑합니다.
이러한 함수는 64비트 산술 연산을 수행할 때 특히 유용합니다. 이렇게 하면 의도한 범위 내에 머물 수 있습니다.
브라우저 지원 및 트랜스파일
이 글을 쓰는 시점에서 Chrome +67 및 Opera +54는 BigInt
데이터 유형을 완벽하게 지원합니다. 불행히도 Edge와 Safari는 아직 구현하지 않았습니다. Firefox는 기본적으로 BigInt
를 지원하지 않지만 about:config
에서 javascript.options.bigint
를 true
로 설정하여 활성화할 수 있습니다. 지원되는 브라우저의 최신 목록은 Can I use…에서 확인할 수 있습니다.
불행히도 BigInt
를 트랜스파일하는 것은 런타임 성능 저하를 초래하는 매우 복잡한 프로세스입니다. 제안이 여러 기존 연산자의 동작을 변경하기 때문에 BigInt
를 직접 폴리필하는 것도 불가능합니다. 현재로서는 더 나은 대안이 BigInt
제안의 순수 JavaScript 구현인 JSBI 라이브러리를 사용하는 것입니다.
이 라이브러리는 네이티브 BigInt
와 정확히 동일하게 동작하는 API를 제공합니다. JSBI를 사용하는 방법은 다음과 같습니다.
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 사용의 장점은 브라우저 지원이 향상되면 코드를 다시 작성할 필요가 없다는 것입니다. 대신 babel 플러그인을 사용하여 JSBI 코드를 기본 BigInt
코드로 자동 컴파일할 수 있습니다. 또한 JSBI의 성능은 기본 BigInt
구현과 동등합니다. 곧 BigInt
에 대한 광범위한 브라우저 지원을 기대할 수 있습니다.
결론
BigInt
는 정수 값이 Number
데이터 유형이 지원하는 범위보다 클 때 사용하기 위한 새로운 데이터 유형입니다. 이 데이터 유형을 사용하면 라이브러리를 사용할 필요 없이 큰 정수에 대한 산술 연산을 안전하게 수행하고, 고해상도 타임스탬프를 나타내고, 큰 정수 ID를 사용하는 등의 작업을 수행할 수 있습니다.
Number
및 BigInt
피연산자를 혼합하여 산술 연산을 수행할 수 없다는 점을 명심하는 것이 중요합니다. 피연산자 중 하나를 명시적으로 변환하여 작업을 수행해야 하는 도메인을 결정해야 합니다. 또한 호환성을 위해 BigInt
에서 단항 더하기( +
) 연산자를 사용할 수 없습니다.
어떻게 생각해? BigInt
가 유용하다고 생각하십니까? 댓글로 알려주세요!