숫자와 문자열

숫자와 문자열 (Numbers and strings)

이 장에서는 JavaScript에서 가장 기본적인 두 데이터 타입인 숫자(numbers)와 문자열(strings)을 소개합니다. 이들의 기저 표현과, 이를 다루고 계산하는 데 사용되는 함수들을 소개하겠습니다.

출처: Numbers and dates

본문

숫자 (Numbers)

JavaScript에서 숫자는 배정밀도 64비트 이진 형식인 IEEE 754로 구현됩니다(즉, ±2^−1022와 ±2^+1023 사이, 대략 ±10^−308부터 ±10^+308까지의 숫자이며, 숫자 정밀도는 53비트). ±2^53 − 1까지의 정수 값은 정확히 표현할 수 있습니다.

부동소수점 숫자를 표현할 수 있는 것 외에도, 숫자 타입에는 Infinity, -Infinity, NaN(not-a-number)의 세 가지 기호 값이 있습니다.

JavaScript의 다른 원시 타입에 대한 맥락은 JavaScript 데이터 타입과 구조를 참고하세요.

네 가지 유형의 숫자 리터럴을 사용할 수 있습니다: 십진(10진), 이진(2진), 팔진(8진), 십육진(16진).

십진수

1234567890
42

십진 리터럴은 0으로 시작한 뒤 십진 숫자가 이어질 수 있지만, 선행 0 뒤의 모든 숫자가 8보다 작으면 그 숫자는 팔진수로 해석됩니다. 이는 레거시 문법으로 간주되며, 0으로 접두된 숫자 리터럴은 팔진수든 십진수든 해석에 관계없이 엄격 모드에서 구문 오류를 일으킵니다 — 그러니 대신 0o 접두어를 사용하세요.

0888 // 888 parsed as decimal
0777 // parsed as octal, 511 in decimal

이진수

이진수 문법은 선행 0 뒤에 소문자 또는 대문자 라틴 문자 "B"가 옵니다(0b 또는 0B). 0b 뒤의 숫자가 0 또는 1이 아니면 "Missing binary digits after 0b"라는 SyntaxError가 발생합니다.

0b10000000000000000000000000000000 // 2147483648
0b01111111100000000000000000000000 // 2139095040
0B00000000011111111111111111111111 // 8388607

팔진수

팔진수의 표준 문법은 0o 접두어를 붙이는 것입니다. 예:

0O755 // 493
0o644 // 420

팔진수에는 레거시 문법도 있습니다 — 팔진수에 0을 접두하는 방식입니다: 0644 === 420, "\045" === "%". 0 뒤의 숫자가 0부터 7 범위 밖이면 그 숫자는 십진수로 해석됩니다.

const n = 0755; // 493
const m = 0644; // 420

엄격 모드는 이 팔진 문법을 금지합니다.

십육진수

십육진수 문법은 선행 0 뒤에 소문자 또는 대문자 라틴 문자 "X"가 옵니다(0x 또는 0X). 0x 뒤의 숫자가 범위(0123456789ABCDEF) 밖이면 "Identifier starts immediately after numeric literal"라는 SyntaxError가 발생합니다.

0xFFFFFFFFFFFFF // 4503599627370495
0xabcdef123456 // 188900967593046
0XA // 10

지수 표기 (Exponentiation)

0e-5 // 0
0e+5 // 0
5e1 // 50
175e-2 // 1.75
1e3 // 1000
1e-3 // 0.001
1E3 // 1000

숫자 구분자 (Numeric separators)

위에 보인 모든 리터럴 문법에서 가독성을 높이기 위해 숫자 사이에 밑줄(_)을 넣을 수 있습니다.

1_000_000_000_000
1_050.95
0b1010_0001_1000_0101
0o2_2_5_6
0xA0_B0_C0
1_000_000_000_000_000_000_000n

숫자 리터럴에 대한 자세한 내용은 어휘 문법 참조 문서를 참고하세요.

Number 객체

내장 Number 객체에는 최대값, NaN, 무한대 같은 숫자 상수에 대한 속성이 있습니다. 이 속성들의 값은 변경할 수 없으며 다음과 같이 사용합니다.

const biggestNum = Number.MAX_VALUE;
const smallestNum = Number.MIN_VALUE;
const infiniteNum = Number.POSITIVE_INFINITY;
const negInfiniteNum = Number.NEGATIVE_INFINITY;
const notANum = Number.NaN;

위와 같이 항상 미리 정의된 Number 객체의 속성으로 참조하며, 직접 만든 Number 객체의 속성으로는 참조하지 않습니다.

다음 표는 Number 객체의 속성을 요약합니다.

속성 설명
Number.MAX_VALUE 표현 가능한 가장 큰 양수 (1.7976931348623157e+308)
Number.MIN_VALUE 표현 가능한 가장 작은 양수 (5e-324)
Number.NaN 특수한 "숫자가 아님" 값
Number.NEGATIVE_INFINITY 특수한 음의 무한대 값; 오버플로 시 반환
Number.POSITIVE_INFINITY 특수한 양의 무한대 값; 오버플로 시 반환
Number.EPSILON 1과 Number로 표현 가능한 1보다 큰 가장 작은 값 사이의 차이 (2.220446049250313e-16)
Number.MIN_SAFE_INTEGER JavaScript의 최소 안전 정수 (−2^53 + 1, 즉 −9007199254740991)
Number.MAX_SAFE_INTEGER JavaScript의 최대 안전 정수 (+2^53 − 1, 즉 +9007199254740991)
메서드 설명
Number.parseFloat() 문자열 인자를 파싱해 부동소수점 숫자를 반환. 전역 parseFloat() 함수와 동일
Number.parseInt() 문자열 인자를 파싱해 지정된 진법(radix/base)의 정수를 반환. 전역 parseInt() 함수와 동일
Number.isFinite() 전달된 값이 유한한 숫자인지 결정
Number.isInteger() 전달된 값이 정수인지 결정
Number.isNaN() 전달된 값이 NaN인지 결정. 원래 전역 isNaN()의 더 견고한 버전
Number.isSafeInteger() 제공된 값이 안전 정수인 숫자인지 결정

Number 프로토타입은 다양한 형식으로 Number 객체에서 정보를 가져오는 메서드를 제공합니다. 다음 표는 Number.prototype의 메서드를 요약합니다.

메서드 설명
toExponential() 지수 표기법으로 숫자를 나타내는 문자열 반환
toFixed() 고정 소수점 표기법으로 숫자를 나타내는 문자열 반환
toPrecision() 고정 소수점 표기법에서 지정된 정밀도로 숫자를 나타내는 문자열 반환

Math 객체

내장 Math 객체에는 수학 상수와 함수에 대한 속성과 메서드가 있습니다. 예를 들어 Math 객체의 PI 속성은 파이(3.141…)의 값을 가지며, 애플리케이션에서 다음과 같이 사용합니다.

Math.PI;

마찬가지로 표준 수학 함수는 Math의 메서드입니다. 여기에는 삼각, 로그, 지수 및 기타 함수가 포함됩니다. 예를 들어 삼각 함수인 사인을 사용하려면 다음과 같이 씁니다.

Math.sin(1.56);

Math의 모든 삼각 메서드는 인자를 라디안(radian) 단위로 받는다는 점에 유의하세요.

다음 표는 Math 객체의 메서드를 요약합니다.

메서드 설명
abs() 절대값
sin(), cos(), tan() 표준 삼각 함수; 인자는 라디안
asin(), acos(), atan(), atan2() 역삼각 함수; 라디안 값 반환
sinh(), cosh(), tanh() 쌍곡선 함수; 인자는 쌍곡선 각도
asinh(), acosh(), atanh() 역쌍곡선 함수; 쌍곡선 각도 값 반환
pow(), exp(), expm1(), log(), log10(), log1p(), log2() 지수 및 로그 함수
floor(), ceil() 인자보다 작거나/크거나 같은 가장 큰/작은 정수 반환
min(), max() 콤마로 구분된 숫자 목록 인자의 최소 또는 최대 값 반환
random() 0과 1 사이의 난수 반환
round(), fround(), trunc() 반올림 및 잘라내기 함수
sqrt(), cbrt(), hypot() 제곱근, 세제곱근, 인자 제곱들의 합의 제곱근
sign() 숫자의 부호(양수, 음수, 또는 0인지)
clz32(), imul() 32비트 이진 표현에서 선행 0 비트 수. 두 인자의 C스타일 32비트 곱셈 결과

많은 다른 객체와 달리 자신만의 Math 객체를 만들지 않습니다. 항상 내장 Math 객체를 사용합니다.

BigInt

숫자 값의 한 가지 단점은 단지 64비트라는 점입니다. 실제로 IEEE 754 인코딩을 사용하므로 Number.MAX_SAFE_INTEGER(2^53 − 1)보다 큰 정수는 정확히 표현할 수 없습니다. 이진 데이터를 인코딩해야 하는 필요를 해결하고 i64(64비트 정수)와 i128(128비트 정수) 같은 넓은 정수를 제공하는 다른 언어들과 상호 운용하기 위해, JavaScript는 임의로 큰 정수를 표현하는 또 다른 데이터 타입인 BigInt도 제공합니다.

BigIntn 접미사가 붙은 정수 리터럴로 정의할 수 있습니다.

const b1 = 123n;
// Can be arbitrarily large.
const b2 = -1234567890987654321n;

BigIntBigInt 생성자를 사용해 숫자 값이나 문자열 값으로부터도 구성할 수 있습니다.

const b1 = BigInt(123);
// Using a string prevents loss of precision, since long number
// literals don't represent what they seem like.
const b2 = BigInt("-1234567890987654321");

개념적으로 BigInt는 정수를 인코딩하는 임의로 긴 비트 시퀀스일 뿐입니다. 정밀도를 잃거나 오버플로/언더플로 없이 안전하게 어떤 산술 연산도 할 수 있습니다.

const integer = 12 ** 34; // 4.9222352429520264e+36; only has limited precision
const bigint = 12n ** 34n; // 4922235242952026704037113243122008064n

숫자와 비교해 BigInt 값은 큰 정수를 표현할 때 더 높은 정밀도를 제공하지만, 부동소수점 숫자는 표현할 수 없습니다. 예를 들어 나눗셈은 0으로 반올림됩니다.

const bigintDiv = 5n / 2n; // 2n, because there's no 2.5 in BigInt

수학 함수(Math)는 BigInt 값에는 사용할 수 없습니다. 숫자에서만 작동합니다.

BigInt와 숫자 사이의 선택은 사용 사례와 입력 범위에 달려 있습니다. 숫자의 정밀도는 대부분의 일상적인 작업을 이미 수용할 수 있으며, BigInt는 이진 데이터를 다루는 데 가장 적합합니다.

BigInt 값으로 할 수 있는 일에 대해 더 알아보려면 식(Expressions)과 연산자(Operators) 섹션 또는 BigInt 참조 문서를 읽으세요.

문자열 (Strings)

JavaScript의 String 타입은 텍스트 데이터를 표현하는 데 사용됩니다. 이는 16비트 부호 없는 정수 값(UTF-16 코드 단위)의 "요소" 집합입니다. String의 각 요소는 String에서 위치를 차지합니다. 첫 번째 요소는 인덱스 0에, 다음은 인덱스 1에, 이런 식입니다. String의 길이는 그 안의 요소 수입니다. 문자열 리터럴이나 문자열 객체를 사용해 문자열을 만들 수 있습니다.

문자열 리터럴

소스 코드에서 단일 또는 이중 따옴표를 사용해 문자열을 선언할 수 있습니다.

'foo'
"bar"

문자열 리터럴 안에서 대부분의 문자는 문자 그대로 입력할 수 있습니다. 유일한 예외는 백슬래시(\, 이스케이프 시퀀스를 시작), 문자열을 감싸는 데 사용되는 따옴표 문자(문자열을 종료), 그리고 백슬래시가 앞에 오지 않으면 구문 오류인 줄바꿈 문자입니다.

이스케이프 시퀀스를 사용해 더 고급 문자열을 만들 수 있습니다.

  • 십육진 이스케이프 시퀀스: \x 뒤의 숫자는 십육진수로 해석됩니다.
    "\xA9" // "©"
    
  • 유니코드 이스케이프 시퀀스: 유니코드 이스케이프 시퀀스는 \u 다음에 최소 네 자리 십육진 숫자가 필요합니다.
    "\u00A9" // "©"
    
  • 유니코드 코드 포인트 이스케이프: 유니코드 코드 포인트 이스케이프를 사용하면 십육진수를 사용해 어떤 문자도 이스케이프할 수 있어서 0x10FFFF까지의 유니코드 코드 포인트를 사용할 수 있습니다. 네 자리 유니코드 이스케이프로는 같은 결과를 얻기 위해 서로게이트 절반을 별도로 써야 하는 경우가 많습니다.
    "\u{2F804}"
    
    // the same with simple Unicode escapes
    "\uD87E\uDC04"
    
    String.fromCodePoint() 또는 String.prototype.codePointAt()도 참고하세요.

String 객체

문자열 값에 직접 메서드를 호출할 수 있습니다.

console.log("hello".toUpperCase()); // HELLO

String 값에 사용할 수 있는 메서드는 다음과 같습니다.

  • 질의 (Query): 특정 문자열 인덱스의 문자 또는 문자 코드를 가져옵니다. at(), charAt(), charCodeAt(), codePointAt() 등이 포함됩니다.
  • 검색 (Search): 패턴에 부합하는 부분 문자열에 대한 정보를 얻거나 특정 부분 문자열이 존재하는지 테스트합니다. indexOf(), lastIndexOf(), startsWith(), endsWith(), includes(), match(), matchAll(), search()가 포함됩니다.
  • 구성 (Composition): 문자열을 더 긴 문자열로 결합합니다. padStart(), padEnd(), concat(), repeat()이 포함됩니다.
  • 분해 (Decomposition): 문자열을 더 작은 문자열로 나눕니다. split(), slice(), substring(), substr(), trim(), trimStart(), trimEnd()이 포함됩니다.
  • 변환 (Transformation): 현재 문자열 내용에 기반한 새 문자열을 반환합니다. toLowerCase(), toUpperCase(), toLocaleLowerCase(), toLocaleUpperCase(), normalize(), toWellFormed()이 포함됩니다.

문자열 작업 시, 문자열 조작에 중요한 기능을 제공하는 두 가지 다른 객체가 있습니다: RegExpIntl입니다. 이들은 각각 정규 표현식과 국제화(i18n) 장에서 소개됩니다.

템플릿 리터럴 (Template literals)

템플릿 리터럴은 삽입된 표현식(embedded expressions)을 허용하는 문자열 리터럴입니다. 여러 줄 문자열과 문자열 보간(string interpolation) 기능을 사용할 수 있습니다.

템플릿 리터럴은 이중 또는 단일 따옴표 대신 백틱(grave accent) 문자()로 둘러싸여 있습니다. 템플릿 리터럴에는 자리 표시자(placeholder)가 포함될 수 있습니다. 이는 달러 기호와 중괄호(${expression}`)로 표시됩니다.

여러 줄 (Multi-lines)

소스에 삽입된 새 줄 문자는 모두 템플릿 리터럴의 일부입니다. 일반 문자열을 사용하면 여러 줄 문자열을 얻기 위해 다음 문법을 써야 합니다.

console.log(
 "string text line 1\n\
string text line 2",
);
// "string text line 1
// string text line 2"

여러 줄 문자열로 같은 효과를 얻기 위해 이제 다음과 같이 쓸 수 있습니다.

console.log(`string text line 1
string text line 2`);
// "string text line 1
// string text line 2"

삽입된 표현식 (Embedded expressions)

일반 문자열 안에 표현식을 삽입하려면 다음 문법을 사용합니다.

const five = 5;
const ten = 10;
console.log(
 "Fifteen is " + (five + ten) + " and not " + (2 * five + ten) + ".",
);
// "Fifteen is 15 and not 20."

이제 템플릿 리터럴을 사용하면 이런 치환을 더 읽기 쉽게 만드는 문법 설탕을 활용할 수 있습니다.

const five = 5;
const ten = 10;
console.log(`Fifteen is ${five + ten} and not ${2 * five + ten}.`);
// "Fifteen is 15 and not 20."

자세한 내용은 JavaScript 참조 문서의 템플릿 리터럴을 읽어보세요.

더 알아보기