숫자와 문자열
숫자와 문자열 (Numbers and strings)
이 장에서는 JavaScript에서 가장 기본적인 두 데이터 타입인 숫자(numbers)와 문자열(strings)을 소개합니다. 이들의 기저 표현과, 이를 다루고 계산하는 데 사용되는 함수들을 소개하겠습니다.
본문
숫자 (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도 제공합니다.
BigInt는 n 접미사가 붙은 정수 리터럴로 정의할 수 있습니다.
const b1 = 123n;
// Can be arbitrarily large.
const b2 = -1234567890987654321n;
BigInt는 BigInt 생성자를 사용해 숫자 값이나 문자열 값으로부터도 구성할 수 있습니다.
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()이 포함됩니다.
문자열 작업 시, 문자열 조작에 중요한 기능을 제공하는 두 가지 다른 객체가 있습니다: RegExp와 Intl입니다. 이들은 각각 정규 표현식과 국제화(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 참조 문서의 템플릿 리터럴을 읽어보세요.