문법과 타입
문법과 타입 (Grammar and types)
이 장은 JavaScript의 기본 문법, 변수 선언, 데이터 타입, 리터럴에 대해 다룬다. JavaScript 가이드의 두 번째 장으로, 언어의 기초인 문법 구조부터 시작해 변수 선언 방식, 데이터 구조와 타입, 그리고 각종 리터럴을 설명한다.
본문
기초 (Basics)
JavaScript는 대부분의 문법을 Java, C, C++에서 빌려왔지만, Awk, Perl, Python의 영향도 받았다.
JavaScript는 **대소문자를 구분(case-sensitive)**하며 Unicode 문자 집합을 사용한다. 예를 들어 독일어로 "일찍"을 뜻하는 단어 Früh는 변수 이름으로 사용할 수 있다.
const Früh = "foobar";
하지만 früh는 JavaScript가 대소문자를 구분하므로 Früh와 같은 변수가 아니다.
JavaScript에서 명령은 **문장(statement)**이라고 하며 **세미콜론(;)**으로 구분된다. 문장이 단독 줄에 쓰이면 세미콜론이 필수는 아니다. 하지만 한 줄에 둘 이상의 문장을 쓰고 싶다면 세미콜론으로 구분해야 한다.
참고: ECMAScript는 문장을 끝내기 위해 자동 세미콜론 삽입(ASI, automatic semicolon insertion) 규칙도 가진다. (자세한 내용은 JavaScript의 어휘 문법에 대한 상세 참조를 보라.)
하지만 문장 뒤에는 꼭 필요하지 않더라도 항상 세미콜론을 쓰는 것이 모범 사례로 여겨진다. 이 관행은 코드에 버그가 생길 가능성을 줄여준다.
JavaScript 스크립트의 소스 텍스트는 왼쪽에서 오른쪽으로 스캔되며, 토큰·제어 문자·줄 종결자·주석·공백인 입력 요소들의 시퀀스로 변환된다. (공백, 탭, 줄바꿈 문자는 공백으로 간주된다.)
주석 (Comments)
주석 문법은 C++과 다른 많은 언어와 동일하다.
// 한 줄 주석
/* 이것은 더 긴,
* 여러 줄 주석
*/
블록 주석은 중첩할 수 없다. 주석에 */ 시퀀스를 실수로 포함하면 그 지점에서 주석이 종료되는 문제가 자주 발생한다.
/* 그러나 /* 주석 중첩 */ 은 SyntaxError */
이 경우 */ 패턴을 깨뜨려야 한다. 예를 들어 백슬래시를 삽입한다.
/* 슬래시를 이스케이프해 /* 주석 중첩 *\/ 할 수 있음 */
주석은 공백처럼 동작하며 스크립트 실행 중에 버려진다.
참고: 일부 JavaScript 파일의 시작 부분에서
#!/usr/bin/env node처럼 보이는 세 번째 유형의 주석 문법도 볼 수 있다. 이를 hashbang 주석 문법이라고 하며, 스크립트를 실행해야 할 특정 JavaScript 엔진의 경로를 지정하는 데 쓰이는 특별한 주석이다. 자세한 내용은 Hashbang comments를 보라.
선언 (Declarations)
JavaScript에는 다섯 종류의 변수 선언이 있다.
var— 변수를 선언하며, 선택적으로 값을 초기화한다.let— 블록 범위(block-scoped) 변수를 선언하며, 선택적으로 값을 초기화한다.const— 재할당할 수 없는 블록 범위 변수를 선언하며, 선언 시에 초기화해야 한다.using—const처럼 선언하되 동기적으로 폐기(dispose)되는 변수.await using—const처럼 선언하되 비동기적으로 폐기되는 변수.
이 글에서는 처음 세 가지 var, let, const만 다룬다. using과 await using 선언은 Resource management 문서에서 소개한다.
변수 (Variables)
변수는 애플리케이션 안의 값에 대한 기호 이름으로 사용한다. 변수의 이름을 **식별자(identifier)**라고 하며 특정 규칙을 따른다.
JavaScript 식별자는 보통 **문자, 밑줄(_), 또는 달러 기호($)**로 시작한다. 이후 문자는 숫자(0–9)도 가능하다. JavaScript는 대소문자를 구분하므로 문자에는 대문자 A–Z와 소문자 a–z가 모두 포함된다.
식별자에는 å, ü 같은 대부분의 Unicode 문자를 사용할 수 있다. (자세한 내용은 어휘 문법 참조를 보라.) 또한 Unicode 이스케이프 시퀀스로 식별자의 문자를 표현할 수도 있다.
유효한 이름의 예로 Number_hits, temp99, $credit, _name 등이 있다.
변수 선언하기
변수는 두 가지 방식으로 선언할 수 있다.
var키워드 사용. 예:var x = 42. 이 문법은 실행 컨텍스트에 따라 지역 변수와 전역 변수를 모두 선언할 수 있다.const또는let키워드 사용. 예:let y = 13. 이 문법은 블록 범위 지역 변수를 선언할 수 있다. (아래 Variable scope 참조.)
또한 구조 분해(destructuring) 문법으로 변수를 선언해 값을 풀어낼 수도 있다. 예: const { bar } = foo는 bar라는 변수를 만들고 객체 foo에서 같은 이름의 키에 해당하는 값을 할당한다.
변수는 사용하기 전에 항상 선언해야 한다. JavaScript는 과거에는 선언되지 않은 변수에 할당하는 것을 허용했는데, 이는 선언되지 않은 전역 변수를 만든다. 이는 strict mode에서는 오류이며 아예 피해야 한다.
선언과 초기화
let x = 42 같은 문장에서 let x 부분을 선언(declaration), = 42 부분을 **초기화자(initializer)**라고 한다. 선언은 코드에서 나중에 변수에 접근할 때 ReferenceError가 발생하지 않게 해주고, 초기화자는 변수에 값을 할당한다. var와 let 선언에서 초기화자는 선택 사항이다. 초기화자 없이 변수를 선언하면 undefined 값이 할당된다.
let x;
console.log(x); // "undefined"를 기록
본질적으로 let x = 42는 let x; x = 42;와 같다.
const 선언은 항상 초기화자가 필요하다. 선언 이후의 어떤 종류의 할당도 금지하므로, undefined로 암묵적으로 초기화하는 것은 프로그래머의 실수일 가능성이 높기 때문이다.
const x; // SyntaxError: Missing initializer in const declaration
변수 범위 (Variable scope)
변수는 다음 범위 중 하나에 속할 수 있다.
- 전역 범위(Global scope) — 스크립트 모드에서 실행되는 모든 코드의 기본 범위.
- 모듈 범위(Module scope) — 모듈 모드에서 실행되는 코드의 범위.
- 함수 범위(Function scope) — 함수와 함께 만들어진 범위.
추가로 let이나 const로 선언된 변수는 추가 범위에 속할 수 있다.
- 블록 범위(Block scope) — 쌍으로 된 중괄호(블록)와 함께 만들어진 범위.
어떤 함수 밖에서 변수를 선언하면 현재 문서의 다른 모든 코드에서 사용할 수 있으므로 전역 변수라고 한다. 함수 안에서 변수를 선언하면 해당 함수 안에서만 사용할 수 있으므로 지역 변수라고 한다.
let과 const 선언은 선언된 블록 문장으로 범위가 한정될 수도 있다.
if (Math.random() > 0.5) {
const y = 5;
}
console.log(y); // ReferenceError: y is not defined
그러나 var로 만든 변수는 블록 범위가 아니라, 블록이 놓인 함수(또는 전역 범위)에만 국한된다. 예를 들어 다음 코드는 5를 기록한다. 왜냐하면 x의 범위가 전역 컨텍스트(코드가 함수의 일부라면 함수 컨텍스트)이기 때문이다. x의 범위는 바로 인접한 if 문장 블록으로 제한되지 않는다.
if (true) {
var x = 5;
}
console.log(x); // x is 5
변수 호이스팅 (Variable hoisting)
var로 선언된 변수는 **호이스팅(hoisted)**된다. 즉 선언에 아직 도달하지 않았더라도 범위 안 어디서든 변수를 참조할 수 있다. var 선언은 함수나 전역 범위의 맨 위로 "끌어올려진" 것처럼 볼 수 있다. 하지만 선언 전에 변수에 접근하면 값은 항상 undefined이다. 선언과 기본 초기화(undefined로)만 호이스팅되고 값 할당은 호이스팅되지 않기 때문이다.
console.log(x === undefined); // true
var x = 3;
(function () {
console.log(x); // undefined
var x = "local value";
})();
위 예제들은 다음과 동일하게 해석된다.
var x;
console.log(x === undefined); // true
x = 3;
(function () {
var x;
console.log(x); // undefined
x = "local value";
})();
호이스팅 때문에 함수 안의 모든 var 문장은 함수 맨 위에 최대한 가깝게 배치해야 한다. 이 모범 사례는 코드의 명확성을 높인다.
let과 const가 호이스팅되는지 여부는 정의 논쟁의 문제다. 변수 선언 전에 블록에서 변수를 참조하면 항상 ReferenceError가 발생한다. 왜냐하면 변수가 블록 시작부터 선언이 처리될 때까지 **"일시적 사각지대(temporal dead zone)"**에 있기 때문이다.
console.log(x); // ReferenceError
const x = 3;
console.log(y); // ReferenceError
let y = 3;
선언만 호이스팅하고 값을 호이스팅하지 않는 var와 달리, 함수 선언은 완전히 호이스팅된다. 즉 범위 안 어디서든 함수를 안전하게 호출할 수 있다. 더 논의는 호이스팅 용어집 항목을 보라.
전역 변수 (Global variables)
전역 변수는 사실 전역 객체의 속성이다.
웹 페이지에서 전역 객체는 window이므로 window.variable 문법으로 전역 변수를 읽고 설정할 수 있다. 모든 환경에서 globalThis 변수(그 자체가 전역 변수)로 전역 변수를 읽고 설정할 수 있다. 이것은 다양한 JavaScript 런타임 간에 일관된 인터페이스를 제공하기 위함이다.
결과적으로, 한 window나 frame에서 선언한 전역 변수를 다른 window나 frame에서 그 이름을 지정해 접근할 수 있다. 예를 들어 phoneNumber라는 변수가 문서에 선언되어 있다면, iframe에서 parent.phoneNumber로 이 변수를 참조할 수 있다.
상수 (Constants)
const 키워드로 읽기 전용의 이름 있는 상수를 만들 수 있다. 상수 식별자의 문법은 일반 변수 식별자와 같다. 문자·밑줄·달러 기호($)로 시작해야 하며 알파벳·숫자·밑줄 문자를 포함할 수 있다.
const PI = 3.14;
상수는 할당을 통해 값을 바꾸거나 스크립트 실행 중 재선언할 수 없다. 값으로 초기화되어야 한다. 상수의 범위 규칙은 let 블록 범위 변수와 동일하다.
같은 범위에서 함수나 변수와 같은 이름으로 상수를 선언할 수 없다. 예:
// 오류 발생
function f() {}
const f = 5;
// 이것도 오류 발생
function f() {
const g = 5;
var g;
}
그러나 const는 재할당만 막을 뿐, 변경(mutation)은 막지 않는다. 상수에 할당된 객체의 속성은 보호되지 않으므로 다음 문장은 문제 없이 실행된다.
const MY_OBJECT = { key: "value" };
MY_OBJECT.key = "otherValue";
또한 배열의 내용도 보호되지 않으므로 다음 문장은 문제 없이 실행된다.
const MY_ARRAY = ["HTML", "CSS"];
MY_ARRAY.push("JAVASCRIPT");
console.log(MY_ARRAY); // ['HTML', 'CSS', 'JAVASCRIPT'];
데이터 구조와 타입 (Data structures and types)
데이터 타입 (Data types)
가장 최신 ECMAScript 표준은 여덟 가지 데이터 타입을 정의한다. 먼저 일곱 가지 프리미티브(원시) 타입:
Boolean—true와false.null— null 값을 나타내는 특별한 키워드. (JavaScript는 대소문자를 구분하므로null은Null,NULL또는 다른 변형과 같지 않다.)undefined— 값이 정의되지 않은 최상위 속성.Number— 정수 또는 부동소수점 숫자. 예:42또는3.14159.BigInt— 임의 정밀도의 정수. 예:9007199254740992n.String— 텍스트 값을 나타내는 문자들의 시퀀스. 예:"Howdy".Symbol— 인스턴스가 유일하고 불변인 데이터 타입.
그리고 Object.
이 데이터 타입들은 상대적으로 적지만 애플리케이션에서 유용한 연산을 수행할 수 있게 한다. 함수는 언어의 또 다른 근본 요소다. 함수는 기술적으로 일종의 객체지만, 객체를 값의 이름 있는 컨테이너로, 함수를 스크립트가 수행할 수 있는 절차로 생각하면 된다.
데이터 타입 변환 (Data type conversion)
JavaScript는 동적으로 타입이 정해지는(dynamically typed) 언어다. 즉 변수를 선언할 때 데이터 타입을 지정할 필요가 없고, 스크립트 실행 중에 데이터 타입이 필요에 따라 자동으로 변환된다. 예를 들어 변수를 다음과 같이 정의했다가:
let answer = 42;
나중에 같은 변수에 문자열 값을 할당할 수 있다.
answer = "Thanks for all the fish!";
JavaScript는 동적 타입이므로 이 할당은 오류 메시지를 발생시키지 않는다.
숫자와 + 연산자 (Numbers and the '+' operator)
+ 연산자와 관련된 숫자·문자열 값이 있는 표현식에서 JavaScript는 숫자 값을 문자열로 변환한다. 예를 들어 다음 문장을 보라.
x = "The answer is " + 42; // "The answer is 42"
y = 42 + " is the answer"; // "42 is the answer"
z = "37" + 7; // "377"
다른 모든 연산자에서 JavaScript는 숫자 값을 문자열로 변환하지 않는다. 예:
"37" - 7; // 30
"37" * 7; // 259
문자열을 숫자로 변환하기 (Converting strings to numbers)
숫자를 나타내는 값이 메모리에 문자열로 저장되어 있는 경우, 변환을 위한 메서드가 있다.
parseInt()parseFloat()Number()
parseInt는 정수만 반환하므로 소수에는 사용이 제한된다.
참고:
parseInt의 모범 사례는 항상 radix(기수) 매개변수를 포함하는 것이다. radix 매개변수는 어떤 숫자 체계를 사용할지 지정하는 데 쓰인다.parseInt("101", 2); // 5
문자열에서 숫자를 얻는 또 다른 방법은 +(단항 플러스) 연산자다. 이는 Number() 함수와 같은 과정인 숫자 변환을 암묵적으로 수행한다.
"1.1" + "1.1"; // '1.11.1'
(+"1.1") + (+"1.1"); // 2.2
// 참고: 괄호는 명확성을 위해 추가된 것이지 필수는 아니다.
리터럴 (Literals)
리터럴은 JavaScript에서 값을 나타낸다. 이들은 변수가 아니라 스크립트에 문자 그대로 제공하는 고정값이다. 이 절에서는 다음 리터럴 타입을 설명한다.
- 배열 리터럴
- Boolean 리터럴
- 숫자 리터럴
- 객체 리터럴
- RegExp 리터럴
- 문자열 리터럴
배열 리터럴 (Array literals)
배열 리터럴은 각각 배열 요소를 나타내는 0개 이상의 표현식의 목록으로, 대괄호([])로 감싼다. 배열 리터럴로 배열을 만들면 지정된 값이 요소로 초기화되고, 길이는 지정된 인수의 개수로 설정된다. 다음 예는 세 요소와 길이 3을 가진 coffees 배열을 만든다.
const coffees = ["French Roast", "Colombian", "Kona"];
배열 리터럴은 리터럴이 평가될 때마다 새 배열 객체를 만든다. 예를 들어 전역 범위에서 리터럴로 정의된 배열은 스크립트가 로드될 때 한 번 생성된다. 그러나 배열 리터럴이 함수 안에 있다면 그 함수가 호출될 때마다 새 배열이 인스턴스화된다.
참고: 배열 리터럴은
Array객체를 만든다.Array객체에 대한 자세한 내용은Array와 Indexed collections를 보라.
배열 리터럴의 추가 쉼표 (Extra commas)
배열 리터럴에서 쉼표를 두 개 연속으로 넣으면 지정되지 않은 요소를 위한 빈 슬롯(empty slot)이 남는다. 다음 예는 fish 배열을 만든다.
const fish = ["Lion", , "Angel"];
이 배열을 기록하면 다음과 같이 보인다.
console.log(fish);
// [ 'Lion', <1 empty item>, 'Angel' ]
두 번째 항목이 "empty"라는 점에 주목하라. 이는 실제 undefined 값과 정확히 같지 않다. Array.prototype.map 같은 배열 순회 메서드를 사용할 때 빈 슬롯은 건너뛴다. 그러나 인덱스 접근인 fish[1]은 여전히 undefined를 반환한다.
요소 목록 끝에 **후행 쉼표(trailing comma)**를 포함하면 그 쉼표는 무시된다. 다음 예에서 배열의 길이는 3이고, myList[3]은 없으며 myList[1]은 비어 있다. 목록의 다른 모든 쉼표는 새 요소를 나타낸다.
const myList = ["home", , "school"];
다음 예에서 배열의 길이는 4이고, myList[0]과 myList[2]가 없다.
const myList = [, "home", , "school"];
다음 예에서 배열의 길이는 4이고, myList[1]과 myList[3]이 없다. 마지막 쉼표만 무시된다.
const myList = ["home", , "school", ,];
참고: 후행 쉼표는 여러 줄 배열에서 git diff를 깔끔하게 유지하는 데 도움이 된다. 끝에 항목을 추가하면 한 줄만 추가될 뿐 이전 줄은 수정되지 않기 때문이다.
const myList = [ "home", "school", + "hospital", ];
추가 쉼표의 동작을 이해하는 것은 JavaScript를 언어로서 이해하는 데 중요하다. 하지만 자신의 코드를 작성할 때는 누락된 요소를 undefined로 명시적으로 선언하거나, 최소한 그 부재를 강조하는 주석을 삽입해야 한다. 이렇게 하면 코드의 명확성과 유지보수성이 높아진다.
const myList = ["home", /* empty */, "school", /* empty */, ];
Boolean 리터럴 (Boolean literals)
Boolean 타입에는 true와 false라는 두 개의 리터럴 값이 있다.
참고: 프리미티브 Boolean 값
true·false를Boolean객체의true·false값과 혼동하지 말라.Boolean객체는 프리미티브 Boolean 데이터 타입을 감싸는 래퍼다. 자세한 내용은Boolean을 보라.
숫자 리터럴 (Numeric literals)
JavaScript 숫자 리터럴에는 서로 다른 진법의 정수 리터럴과 10진 부동소수점 리터럴이 포함된다. 언어 사양은 숫자 리터럴이 **부호 없음(unsigned)**이어야 한다고 요구한다. 그럼에도 -123.4 같은 코드 조각은 괜찮다. 단항 - 연산자가 숫자 리터럴 123.4에 적용된 것으로 해석되기 때문이다.
정수 리터럴 (Integer literals)
정수와 BigInt 리터럴은 10진(base 10), 16진(base 16), 8진(base 8), 2진(base 2)으로 쓸 수 있다.
- 10진 정수 리터럴은 앞에 0이 없는 숫자들의 시퀀스다.
- 정수 리터럴의 선행 0(영), 또는 선행
0o(또는0O)는 8진을 나타낸다. 8진 정수 리터럴은 오직 숫자 0–7만 포함할 수 있다. - 선행
0x(또는0X)는 16진 정수 리터럴을 나타낸다. 16진 정수는 숫자(0–9)와 문자 a–f 및 A–F를 포함할 수 있다. (문자의 대소문자는 값을 바꾸지 않는다. 따라서0xa = 0xA = 10이고0xf = 0xF = 15이다.) - 선행
0b(또는0B)는 2진 정수 리터럴을 나타낸다. 2진 정수 리터럴은 오직 숫자 0과 1만 포함할 수 있다. - 정수 리터럴의 후행
n접미사는 BigInt 리터럴을 나타낸다. BigInt 리터럴은 위의 어떤 진법도 사용할 수 있다. 선행 0의 8진 문법인0123n같은 것은 허용되지 않지만0o123n은 괜찮다.
정수 리터럴의 예:
0,117,123456789123456789n(10진, base 10)015,0001,0o777777777777n(8진, base 8)0x1123,0x00111,0x123456789ABCDEFn(16진, "hex" 또는 base 16)0b11,0b0011,0b11101001010101010101n(2진, base 2)
자세한 내용은 Lexical grammar 참조의 Numeric literals를 보라.
부동소수점 리터럴 (Floating-point literals)
부동소수점 리터럴은 다음 부분을 가질 수 있다.
- 부호 없는 10진 정수,
- 소수점(
.), - 분수(또 다른 10진 숫자),
- 지수(exponent).
지수 부분은 e 또는 E 다음에 정수가 오는 형태로, 부호를 가질 수 있다(+ 또는 -가 앞섬). 부동소수점 리터럴은 최소한 하나의 숫자와, 소수점 또는 e(또는 E)를 하나 이상 가져야 한다. 더 간결하게 문법은 다음과 같다.
[digits].[digits][(E|e)[(+|-)]digits]
예:
3.1415926
.123456789
3.1E+12
.1e-23
객체 리터럴 (Object literals)
객체 리터럴은 객체의 속성 이름과 관련 값 쌍의 목록을 중괄호({})로 감싼 것이다.
⚠️ 경고: 문장의 시작에 객체 리터럴을 사용하지 말라!
{가 블록의 시작으로 해석되기 때문에 오류(또는 예상과 다른 동작)가 발생한다.
다음은 객체 리터럴의 예다. car 객체의 첫 요소는 myCar 속성을 정의하고 새 문자열 "Saturn"을 할당한다. 두 번째 요소 getCar 속성은 함수 호출(carTypes("Honda"))의 결과를 즉시 할당받는다. 세 번째 요소 special 속성은 기존 변수(sales)를 사용한다.
const sales = "Toyota";
function carTypes(name) {
return name === "Honda" ? name : `Sorry, we don't sell ${name}.`;
}
const car = { myCar: "Saturn", getCar: carTypes("Honda"), special: sales };
console.log(car.myCar); // Saturn
console.log(car.getCar); // Honda
console.log(car.special); // Toyota
추가로 속성 이름에 숫자나 문자열 리터럴을 사용하거나 다른 객체 안에 객체를 중첩할 수도 있다. 다음 예는 이런 옵션들을 사용한다.
const car = { manyCars: { a: "Saab", b: "Jeep" }, 7: "Mazda" };
console.log(car.manyCars.b); // Jeep
console.log(car[7]); // Mazda
객체 속성 이름은 빈 문자열을 포함한 어떤 문자열이든 될 수 있다. 속성 이름이 유효한 JavaScript 식별자나 숫자가 아니라면 반드시 따옴표로 감싸야 한다.
유효한 식별자가 아닌 속성 이름은 점(.) 속성으로 접근할 수 없다.
const unusualPropertyNames = {
"": "An empty string",
"!": "Bang!",
};
console.log(unusualPropertyNames.""); // SyntaxError: Unexpected string
console.log(unusualPropertyNames.!); // SyntaxError: Unexpected token !
대신 **대괄호 표기법([])**으로 접근해야 한다.
console.log(unusualPropertyNames[""]); // An empty string
console.log(unusualPropertyNames["!"]); // Bang!
향상된 객체 리터럴 (Enhanced Object literals)
객체 리터럴은 다양한 축약 문법을 지원한다. 여기에는 생성 시 프로토타입 설정, foo: foo 할당의 축약, 메서드 정의, super 호출, 표현식으로 계산된 속성 이름이 포함된다. 이를 함께 사용하면 객체 리터럴과 클래스 선언이 더 가까워지고, 객체 기반 설계도 같은 편의의 일부를 누릴 수 있다.
const theProtoObj = {};
const handler = {};
const obj = {
// __proto__
__proto__: theProtoObj,
// 'handler: handler'의 축약
handler,
// 메서드
toString() {
// super 호출
return `d ${super.toString()}`;
},
// 계산된(동적) 속성 이름
["prop_" + (() => 42)()]: 42,
};
RegExp 리터럴 (RegExp literals)
정규식 리터럴(나중에 자세히 정의됨)은 슬래시로 감싼 패턴이다. 다음은 정규식 리터럴의 예다.
const re = /ab+c/;
문자열 리터럴 (String literals)
문자열 리터럴은 큰따옴표(") 또는 작은따옴표(')로 감싼 0개 이상의 문자다. 문자열은 같은 종류의 따옴표로 구분되어야 한다(즉 둘 다 작은따옴표이거나 둘 다 큰따옴표여야 한다).
다음은 문자열 리터럴의 예들이다.
'foo'
"bar"
'1234'
'one line \n another line'
"Joyo's cat"
특별히 String 객체가 필요하지 않다면 문자열 리터럴을 사용해야 한다. String 객체에 대한 자세한 내용은 String을 보라.
문자열 리터럴 값에서 String 객체의 어떤 메서드든 호출할 수 있다. JavaScript는 자동으로 문자열 리터럴을 임시 String 객체로 변환하고, 메서드를 호출한 뒤 임시 String 객체를 버린다. 문자열 리터럴에서 length 속성도 사용할 수 있다.
// 공백을 포함한 문자열의 기호 수를 출력한다.
console.log("Joyo's cat".length); // 이 경우 10.
**템플릿 리터럴(Template literals)**도 사용할 수 있다. 템플릿 리터럴은 큰따옴표나 작은따옴표 대신 백틱(`)(grave accent) 문자로 감싼다.
템플릿 리터럴은 문자열을 만드는 **문법적 설탕(syntactic sugar)**을 제공한다. (이는 Perl, Python 등의 문자열 보간 기능과 비슷하다.)
// 기본 리터럴 문자열 생성
`In JavaScript '\n' is a line-feed.`;
// 여러 줄 문자열
`In JavaScript, template strings can run
over multiple lines, but double and single
quoted strings cannot.`;
// 문자열 보간
const name = "Lev";
const time = "today";
`Hello ${name}, how are you ${time}?`;
**태그드 템플릿(Tagged templates)**은 템플릿 리터럴과 그 파싱을 위한 "태그(tag)" 함수 호출을 함께 지정하는 간결한 문법이다. 태그드 템플릿은 문자열과 관련 값 집합을 처리하는 함수를 호출하는 더 간결하고 의미 있는 방식일 뿐이다. 템플릿 태그 함수의 이름은 템플릿 리터럴 앞에 온다. 다음 예에서 템플릿 태그 함수의 이름은 print다. print 함수는 인자들을 보간하고 등장할 수 있는 객체나 배열을 직렬화해서 성가신 [object Object]를 피한다.
const formatArg = (arg) => {
if (Array.isArray(arg)) {
// 글머리 기호 목록 출력
return arg.map((part) => `- ${part}`).join("\n");
}
if (arg.toString === Object.prototype.toString) {
// 이 객체는 "[object Object]"로 직렬화될 것이다.
// 더 나은 것을 출력하자.
return JSON.stringify(arg);
}
return arg;
};
const print = (segments, ...args) => {
// 잘 구성된 템플릿 리터럴에는 항상 N개의 인자와
// (N+1)개의 문자열 세그먼트가 있다.
let message = segments[0];
segments.slice(1).forEach((segment, index) => {
message += formatArg(args[index]) + segment;
});
console.log(message);
};
const todos = [
"Learn JavaScript",
"Learn Web APIs",
"Set up my website",
"Profit!",
];
const progress = { javascript: 20, html: 50, css: 10 };
print`I need to do:
${todos}
My current progress is: ${progress}
`;
// I need to do:
// - Learn JavaScript
// - Learn Web APIs
// - Set up my website
// - Profit!
// My current progress is: {"javascript":20,"html":50,"css":10}
태그드 템플릿 리터럴은 함수 호출의 설탕일 뿐이므로 위를 동등한 함수 호출로 다시 쓸 수 있다.
print(["I need to do:\n", "\nMy current progress is: ", "\n"], todos, progress);
이는 console.log 스타일의 보간을 연상시킬 수 있다.
console.log("I need to do:\n%o\nMy current progress is: %o\n", todos, progress);
태그드 템플릿이 변수와 템플릿 자체를 따로 선언해야 하는 전통적인 "포맷터(formatter)" 함수보다 더 자연스럽게 읽히는 것을 볼 수 있다.
문자열에서 특수 문자 사용하기
일반 문자 외에도 다음 예처럼 문자열에 특수 문자를 포함할 수 있다.
"one line \n another line";
다음 표는 JavaScript 문자열에서 사용할 수 있는 특수 문자를 나열한다.
| 문자 | 의미 |
|---|---|
\0 |
Null Byte |
\b |
Backspace |
\f |
Form Feed |
\n |
New Line (줄바꿈) |
\r |
Carriage Return |
\t |
Tab |
\v |
Vertical tab |
\' |
아포스트로피 또는 작은따옴표 |
\" |
큰따옴표 |
\\ |
백슬래시 문자 |
\XXX |
0~377 사이의 최대 3개의 8진수 XXX로 지정된 Latin-1 인코딩 문자. 예: \251은 저작권 기호의 8진 시퀀스. |
\xXX |
00~FF 사이의 두 16진수 XX로 지정된 Latin-1 인코딩 문자. 예: \xA9는 저작권 기호의 16진 시퀀스. |
\uXXXX |
네 16진수 XXXX로 지정된 Unicode 문자. 예: \u00A9는 저작권 기호의 Unicode 시퀀스. Unicode 이스케이프 시퀀스 참조. |
\u{XXXXX} |
Unicode 코드 포인트 이스케이프. 예: \u{2F804}는 Unicode 이스케이프 \uD87E\uDC04와 같음. |
문자 이스케이프 (Escaping characters)
표에 없는 문자에 대해서는 앞의 백슬래시가 무시되지만, 이 용법은 폐기(deprecated)되었으므로 피해야 한다.
문자열 안에 따옴표를 넣으려면 백슬래시를 앞에 붙이면 된다. 이를 따옴표 이스케이프라고 한다. 예:
const quote = "He read \"The Cremation of Sam McGee\" by R.W. Service.";
console.log(quote);
결과는 다음과 같다.
He read "The Cremation of Sam McGee" by R.W. Service.
문자열 안에 문자 그대로의 백슬래시를 포함하려면 백슬래시 문자를 이스케이프해야 한다. 예를 들어 파일 경로 c:\temp를 문자열에 할당하려면 다음을 사용한다.
const home = "c:\\temp";
백슬래시를 앞에 붙여 줄 바꿈을 이스케이프할 수도 있다. 백슬래시와 줄 바꿈은 문자열 값에서 모두 제거된다.
const str =
"this string \
is broken \
across multiple \
lines.";
console.log(str); // this string is broken across multiple lines.
더 알아보기 (More information)
이 장은 선언과 타입의 기본 문법에 초점을 맞췄다. JavaScript의 언어 구성에 대해 더 배우려면 이 가이드의 다음 장들도 보라.
- Control flow and error handling 가이드
- Loops and iteration
- Functions
- Expressions and operators 가이드
다음 장에서는 제어 흐름 구성과 오류 처리를 살펴볼 것이다.
더 알아보기
- JavaScript 가이드: 제어 흐름과 오류 처리
- JavaScript 가이드: 반복과 순회(Loops and iteration)
- JavaScript 가이드: 함수(Functions)
- JavaScript 가이드: 표현식과 연산자(Expressions and operators)
- 키워드: 문법, 변수, var, let, const, 호이스팅, 데이터 타입, 리터럴, 템플릿 리터럴, 식별자, ASI