자바스크립트 기초 #6 문자열과 템플릿 리터럴

#5 객체와 배열 에서 데이터를 묶는 두 자료구조를 봤습니다. 이번 글에서는 문자열 하나를 깊이 살펴봅니다. 자주 쓰는 메서드, 템플릿 리터럴, 그리고 정규식 기본까지 정리합니다.

문자열 만들기 — 따옴표 세 가지 #

자바스크립트에서 문자열을 만드는 따옴표는 셋입니다.

세 가지 문자열
const a = '작은따옴표';
const b = "큰따옴표";
const c = `백틱(템플릿 리터럴)`;

'(작은) 와 "(큰)는 의미상 차이 없습니다. 팀 컨벤션 따라 한 종류로 통일 하는 게 보통입니다. 이 시리즈는 작은따옴표를 씁니다.

세 번째인 백틱은 템플릿 리터럴 이라 부르는 강력한 문자열 형태인데, 잠시 뒤에 자세히 봅니다.

자주 쓰는 메서드 #

길이와 인덱스 접근 #

기본 정보
const s = '자바스크립트';

s.length;      // 7
s[0];          // '자'
s.at(0);       // '자'
s.at(-1);      // '트' (음수 인덱스 — at만 가능)

at()은 ES2022에 추가된 메서드. 음수 인덱스로 끝에서부터 접근할 수 있습니다. s[s.length - 1]보다 짧고 명확합니다.

찾기 #

찾기 / 포함 검사
const s = 'hello world';

s.includes('world');     // true
s.indexOf('world');       // 6
s.indexOf('foo');         // -1 (없으면 -1)
s.startsWith('hello');    // true
s.endsWith('world');      // true

**검색은 거의 항상 includes / startsWith / endsWith**가 직관적입니다. indexOf는 위치까지 알아야 할 때만.

자르기 / 추출 #

부분 문자열
const s = 'hello world';

s.slice(0, 5);       // 'hello'
s.slice(6);          // 'world'
s.slice(-5);         // 'world' (끝에서 5자)
s.substring(0, 5);   // 'hello' (slice과 거의 같음)

옛날에는 substring/substr/slice가 미묘하게 달랐는데, 새 코드에서는 slice 하나로 통일 하는 게 좋습니다. 음수 인덱스도 받고 가장 직관적입니다.

변환 / 정리 #

변환
const s = '  Hello World  ';

s.trim();              // 'Hello World'
s.trimStart();         // 'Hello World  '
s.trimEnd();           // '  Hello World'
s.toLowerCase();       // '  hello world  '
s.toUpperCase();       // '  HELLO WORLD  '
s.replaceAll(' ', '_'); // '__Hello_World__'

replaceAll은 ES2021에 추가됐습니다. 옛날에는 replace(/g/)로 정규식을 써야 했는데 이제 단순 치환은 이쪽이 깔끔합니다.

분할 / 결합 #

split / join
const s = '사과,바나나,포도';

s.split(',');                 // ['사과', '바나나', '포도']
['사과', '바나나'].join(',');  // '사과,바나나'

// 한 글자씩
'hello'.split('');            // ['h', 'e', 'l', 'l', 'o']

// 빈 문자열로 합치기
['h', 'i'].join('');          // 'hi'

split('') 한 글자씩 분리는 ASCII 외 문자(이모지 등)에서는 깨질 수 있습니다. 이모지/한자까지 안전한 분리는 [...s] (spread)나 Array.from(s)를 씁니다.

유니코드 안전한 분리
const s = 'a😀b';
s.split('');          // ['a', '\uD83D', '\uDE00', 'b']  ← 깨짐
[...s];               // ['a', '😀', 'b']
Array.from(s);        // ['a', '😀', 'b']

템플릿 리터럴 — 백틱의 진가 #

+로 문자열을 합치는 경우는 거의 모두 백틱이 더 깔끔합니다.

문자열 합성
const name = '커티스';
const age = 30;

// + 연산
const a = '안녕, ' + name + ' (' + age + ')';

// 템플릿 리터럴
const b = `안녕, ${name} (${age})`;

${...} 안에는 어떤 표현식이든 들어갈 수 있습니다.

const items = ['사과', '바나나', '포도'];

`총 ${items.length}개`;
`첫 번째: ${items[0]}`;
`합: ${1 + 2 + 3}`;
`상태: ${age >= 18 ? '성인' : '미성년'}`;

여러 줄 문자열 #

여러 줄
const html = `
  <div>
    <h1>제목</h1>
    <p>본문</p>
  </div>
`;

옛날에는 '<div>\n<h1>...'처럼 \n으로 줄바꿈을 직접 적었습니다. 백틱은 줄바꿈이 그대로 들어갑니다.

Tagged Template — 함수 호출 #

조금 고급 사용법. 백틱 앞에 함수를 두면 템플릿이 그 함수의 인자로 전달됩니다.

tagged template
function highlight(strings, ...values) {
  return strings.reduce((acc, s, i) => {
    return acc + s + (values[i] !== undefined ? `[${values[i]}]` : '');
  }, '');
}

const name = '커티스';
const age = 30;
highlight`이름은 ${name}, 나이는 ${age}입니다`;
// '이름은 [커티스], 나이는 [30]입니다'

html 같은 라이브러리에서 SQL/HTML 인젝션을 막기 위해 자주 쓰는 패턴입니다. 처음에는 익숙하지 않아도 OK — 만나면 그제서야 자세히 보면 됩니다.

숫자/문자열 변환 #

숫자와 문자열 사이
String(42);              // '42'
(42).toString();         // '42'
`${42}`;                 // '42' — 가장 흔한 관용구

Number('42');             // 42
parseInt('42px');         // 42 — 앞부분만
parseFloat('3.14');       // 3.14
+'42';                    // 42 — 단항 + 연산자

Number('abc');            // NaN
parseInt('abc');          // NaN

Number(...)는 전체가 숫자가 아니면 NaN. parseInt/parseFloat앞에서부터 가능한 만큼 파싱합니다. 입력에 42px 같은 단위가 붙어 있으면 후자가 적합합니다.

정규식 — 패턴 매칭 #

/패턴/플래그 형태의 리터럴.

정규식 기본
const re = /hello/i;       // 대소문자 무시
'Hello World'.match(re);   // ['Hello', ...]
re.test('Hi');             // false
re.test('Hello');          // true

자주 쓰는 메타 문자 #

패턴의미
.임의의 한 글자
\d숫자
\w단어 글자 (알파벳/숫자/_)
\s공백
^ / $줄 시작 / 끝
+한 번 이상
*0번 이상
?0번 또는 한 번
[abc]a, b, c 중 하나
(...)캡처 그룹

자주 쓰는 경우 #

검사 / 추출 / 치환
// 이메일 형식 대충 검사
/^[^@]+@[^@]+\.[^@]+$/.test('me@example.com');   // true

// 숫자만 추출
'price: 1500원'.match(/\d+/);   // ['1500', ...]

// 모든 매치
'a1 b2 c3'.matchAll(/[a-z]\d/g);  // 이터러블

// 치환
'2026-05-04'.replace(/-/g, '/');  // '2026/05/04'

g 플래그는 모든 매치를 찾으라는 뜻(global). 없으면 첫 번째만 찾습니다.

캡처 그룹 #

캡처 그룹으로 분리
const date = '2026-05-04';
const m = date.match(/^(\d{4})-(\d{2})-(\d{2})$/);
// m: ['2026-05-04', '2026', '05', '04', ...]

const [, year, month, day] = m;
console.log(year, month, day);   // 2026 05 04

소괄호 (...) 안의 부분이 캡처 되어 결과 배열에 함께 담깁니다. 명명 그룹도 가능합니다.

명명 캡처
const m = '2026-05-04'.match(
  /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/
);
m.groups.year;    // '2026'
m.groups.month;   // '05'
m.groups.day;     // '04'

(?<이름>...) 형태. 결과의 groups에서 이름으로 꺼내요.

정규식이 필요할 때 / 아닐 때 #

정규식은 강력하지만 읽기 어려워지기 쉽습니다. 다음 경우엔 정규식보다 일반 문자열 메서드가 거의 항상 더 좋습니다.

이건 정규식 쓸 필요 없음
// 단순 검색
s.includes('foo');               // O
s.match(/foo/);                  // X (과함)

// 시작/끝 검사
s.startsWith('http');            // O
s.match(/^http/);                // X

// 단순 치환
s.replaceAll('foo', 'bar');      // O
s.replace(/foo/g, 'bar');        // X (과함)

정규식이 빛나는 상황은 패턴이 가변적이거나 캡처가 필요한 경우입니다 — 날짜, 이메일 같은 형식 검사, 로그 파싱 등.

마무리 #

이번 글에서 정리한 내용:

  • 따옴표 세 가지 — '/"는 의미 같음, ` 는 템플릿 리터럴
  • 자주 쓰는 메서드 — length/at/includes/slice/split/join/replaceAll
  • 유니코드 안전한 분리는 [...s] 또는 Array.from(s)
  • 템플릿 리터럴 — ${} 안에 식, 여러 줄 문자열
  • 변환 — String()/Number()/parseInt(), +값 관용구
  • 정규식 기본 — 메타 문자, g 플래그, 캡처 그룹
  • 단순 검색,치환에는 정규식보다 메서드가 더 명확

다음 글(#7 모듈)에서는 시리즈 마지막으로 — 코드를 여러 파일로 나누는 ES Modules, import/export의 패턴들을 정리합니다.

X