JavaScript / startsWith()로 문자열의 시작 부분 검사하기

String.startsWith(searchString)는 문자열이 지정한 글자로 시작하는지 검사해 true 또는 false를 반환합니다. position을 주면 문자열 전체의 첫 글자가 아니라 그 위치에서 시작하는 부분을 검사합니다. 단순히 어딘가에 포함되는지를 알고 싶다면 includes()와 목적을 구분하세요.

문자열 맨 앞이 맞는지 검사하기

찾는 글자는 맨 앞부터 순서대로 정확히 같아야 합니다. 공백과 대소문자도 비교에 포함되며, 원본 문자열은 바뀌지 않습니다. 파일 이름 접두어나 명령어 앞부분을 확인할 때 사용할 수 있지만, 접두어만 같다고 그 뒤 구조까지 맞는다고 단정해서는 안 됩니다.

console.log('JavaScript'.startsWith('Java')); // true
console.log('JavaScript'.startsWith('Script')); // false
console.log('JavaScript'.startsWith('java')); // false
console.log(' JavaScript'.startsWith('Java')); // false

빈 문자열은 어느 문자열의 시작에도 맞아 true입니다. 검색어가 반드시 있어야 한다면 먼저 빈 입력을 확인하세요. 정규식을 인수로 전달하면 TypeError가 발생합니다. MDN의 String.startsWith() 문서에 인수의 의미가 정리되어 있습니다.

position에서 시작하는 부분 검사하기

text.startsWith(searchString, position)은 지정한 위치에서 바로 검색어가 시작하는지 검사합니다. includes(searchString, position)는 그 위치 이후 어디에 나타나도 참이지만, startsWith()는 바로 그 자리부터 같아야 참입니다.

const text = 'abzcd';
console.log(text.startsWith('z'));     // false
console.log(text.startsWith('z', 2));  // true
console.log(text.startsWith('z', 1));  // false
console.log(text.includes('z', 1));    // true: 뒤쪽까지 검색

위 문자열의 인덱스 2는 z입니다. 문자열 위치는 UTF-16 코드 단위 기준이므로 일부 이모지를 지나는 위치를 직접 계산할 때는 주의하세요. 끝 위치를 지정하는 endsWith()와도 두 번째 인수의 역할이 다릅니다. String.includes()로 포함 여부 확인하기 및 String.endsWith()로 끝 문자열 확인하기를 함께 비교할 수 있습니다.

경로 접두어를 검사할 때의 범위

URL 경로가 /docs/ 아래에 있는지 확인한다면 startsWith("/docs/")처럼 경계 슬래시까지 포함해야 /docs-old와 구분됩니다. URL 전체 문자열에 허용 도메인 접두어만 비교하는 것은 안전한 출처 검사 방법이 아닙니다. 호스트 뒤에 다른 글자가 붙은 주소도 통과할 수 있기 때문입니다.

const url = new URL('https://example.com/docs/intro');
console.log(url.pathname.startsWith('/docs/')); // true
console.log('/docs-old'.startsWith('/docs/'));   // false
console.log(url.origin === 'https://example.com'); // true

주소의 출처를 제한하려는 목적이라면 먼저 new URL(address)로 해석하고 origin을 정확히 비교하세요. 경로 접두어 검사와 출처 검사는 서로 다른 조건입니다. MDN의 URL.origin 문서에서 출처의 구성 요소를 확인할 수 있습니다.

전체 예제: 검사 위치 바꾸기

아래 코드를 UTF-8로 string-starts-with.html에 저장해 브라우저에서 엽니다. 시작 문자열과 위치를 바꾸면 검사 대상 부분과 결과가 바로 표시됩니다. 위치 사용을 해제하면 다시 문자열 맨 앞만 검사합니다.

<!doctype html>
<html lang="ko">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>문자열 시작 검사</title>
</head>
<body>
<label for="text">원본 문자열</label>
<input id="text" type="text" value="abzcd">
<label for="prefix">시작 문자열</label>
<input id="prefix" type="text" value="z">
<label><input id="use-position" type="checkbox"> 검사 위치 사용</label>
<label for="position">검사 위치</label>
<input id="position" type="number" min="0" step="1" value="2" disabled>
<pre id="output" aria-live="polite"></pre>
<script>
const text = document.querySelector('#text');
const prefix = document.querySelector('#prefix');
const usePosition = document.querySelector('#use-position');
const position = document.querySelector('#position');
const output = document.querySelector('#output');

function show() {
  const index = Number(position.value);
  if (usePosition.checked && (position.value.trim() === '' ||
      !Number.isInteger(index) || index < 0)) {
    output.textContent = '검사 위치에는 0 이상의 정수를 입력하세요.';
    return;
  }
  position.disabled = !usePosition.checked;
  const value = text.value;
  const target = prefix.value;
  const part = usePosition.checked ? value.slice(index) : value;
  const found = usePosition.checked
    ? value.startsWith(target, index) : value.startsWith(target);
  output.textContent = `검사 대상 부분: ${JSON.stringify(part)}\n` +
    `시작 문자열: ${JSON.stringify(target)}\n` +
    `startsWith() 결과: ${found}`;
}

text.addEventListener('input', show);
prefix.addEventListener('input', show);
usePosition.addEventListener('change', show);
position.addEventListener('input', show);
show();
</script>
</body>
</html>

기본 문자열 abzcd는 z로 시작하지 않으므로 false입니다. 위치 사용을 켜고 2를 입력하면 검사 대상은 zcd이며 true입니다. 1로 바꾸면 bzcd가 대상이므로 false입니다. 시작 문자열을 비우면 true로 바뀝니다.