어제 오늘 내일

[Javascript] "use strict"란? — 자바스크립트 엄격 모드 완전 정리 본문

IT/Javascript

[Javascript] "use strict"란? — 자바스크립트 엄격 모드 완전 정리

hi.anna 2026. 8. 8. 22:14

자바스크립트 코드를 읽다 보면 파일 맨 위에 덩그러니 놓인 이 한 줄을 종종 만나게 됩니다.

"use strict";

문법도 아니고 함수 호출도 아닌, 그냥 문자열 하나. 처음 보면 "이게 왜 여기 있지?" 싶습니다. 이 글에서는 이 한 줄이 정확히 무엇을 바꾸는지, 그리고 모던 자바스크립트에서도 여전히 필요한지 정리해 보겠습니다.
 

왜 생겼나

자바스크립트는 초창기부터 "관대한" 언어였습니다. 오타를 내도, 말이 안 되는 코드를 써도 최대한 에러 없이 굴러가게 만들어졌죠. 브라우저 입장에서는 스크립트 하나 잘못됐다고 페이지 전체가 멈추는 것보다 나은 선택이었습니다.
문제는 이 관대함이 곧 버그 은폐 장치로 작동한다는 점입니다. 오타 하나가 조용히 전역 변수를 만들고, 잘못된 대입이 아무 일도 없었다는 듯 무시됩니다. 그래서 ES5(2009)에서 등장한 것이 엄격 모드(strict mode)입니다.
핵심 아이디어는 이렇습니다. 기존 코드를 깨뜨리지 않으면서, 원하는 사람만 더 엄격한 규칙을 선택할 수 있게 하자. 새로운 문법을 추가하면 구형 브라우저가 파싱 에러를 내니, 구형 브라우저가 무시해도 안전한 "문자열 리터럴"이라는 형태를 택한 것입니다. 지시어(directive)라고 부릅니다.
 

어떻게 적용하나

적용 범위는 두 가지입니다.
스크립트 전체에 적용 — 파일 맨 위에 선언합니다.

"use strict";

function foo() { /* 여기도 엄격 모드 */ }

함수 단위로 적용 — 함수 본문 맨 위에 선언합니다.

function strictFunc() {
  "use strict";
  // 이 함수 안에서만 엄격 모드
}

function sloppyFunc() {
  // 여기는 그대로 느슨한 모드
}

두 경우 모두 반드시 맨 위여야 합니다. 앞에 주석은 와도 되지만, 실행되는 코드가 한 줄이라도 먼저 오면 지시어로 인식되지 않고 그냥 쓸모없는 문자열이 됩니다.

const x = 1;
"use strict";  // ❌ 아무 효과 없음. 그냥 문자열.

에러도 경고도 없이 조용히 무시되기 때문에, 이 실수는 꽤 오래 발견되지 않을 수 있습니다.
 

무엇이 바뀌나

1. 선언 없는 변수 할당 금지

가장 자주 겪는 변화입니다.

function count() {
  totl = 0;  // total 오타
  return totl;
}

느슨한 모드에서는 totl전역 변수로 자동 생성됩니다. 에러도 없고, 심지어 동작도 합니다. 다만 전역 스코프가 오염되고, 나중에 다른 코드와 충돌하면 원인을 찾기 지옥 같아집니다.

엄격 모드에서는 즉시 ReferenceError: totl is not defined가 발생합니다. 오타를 그 자리에서 잡아주는 거죠.

2. 조용한 실패가 예외로 바뀜

느슨한 모드는 실패해도 아무 말이 없습니다.

const obj = Object.freeze({ name: "kim" });
obj.name = "lee";
console.log(obj.name);  // "kim" — 대입이 무시됨. 에러 없음.

엄격 모드에서는 TypeError가 던져집니다. 다음 경우들이 모두 해당됩니다.

  • 읽기 전용 속성에 대입
  • getter만 있고 setter가 없는 속성에 대입
  • 확장 불가능한(Object.preventExtensions) 객체에 새 속성 추가
  • 삭제 불가능한 속성에 delete (예: delete Object.prototype)

의도가 실패했으면 실패했다고 알려주는 편이 낫습니다.

3. 일반 함수 호출 시 가

function whoAmI() {
  return this;
}

whoAmI();  // 느슨한 모드: globalThis (브라우저에서는 window)
           // 엄격 모드: undefined

느슨한 모드에서는 thisundefinednull이면 전역 객체로 자동 치환됩니다. 이걸 "this 강제 변환(boxing)"이라고 합니다. 원시값을 넘겨도 래퍼 객체로 감싸집니다.

function showType() {
  console.log(typeof this);
}

showType.call(42);  // 느슨한 모드: "object" (Number 래퍼)
                    // 엄격 모드: "number"

메서드를 떼어내서 호출했을 때 조용히 전역 객체를 건드리는 사고를 막아줍니다.

4. 매개변수 이름 중복 금지

function sum(a, a, c) {  // 엄격 모드: SyntaxError
  return a + a + c;
}

느슨한 모드에서는 뒤쪽 a가 이긴다는 규칙으로 동작합니다. 하지만 이건 거의 확실히 실수죠.

5. 와 매개변수의 연결 해제

function update(x) {
  x = 99;
  return arguments[0];
}

update(1);  // 느슨한 모드: 99 (연결되어 함께 바뀜)
            // 엄격 모드: 1 (호출 시점 값 그대로)

느슨한 모드에서 매개변수와 arguments는 서로 살아있는 연결을 유지합니다. 하나를 바꾸면 다른 쪽도 바뀝니다. 직관에 어긋나고 최적화도 방해하므로 엄격 모드에서는 끊어집니다.

또한 argumentseval에 대입하는 것 자체가 금지됩니다.

6. 8진수 리터럴 금지

const n = 0755;  // 엄격 모드: SyntaxError
const m = 0o755; // ✅ ES6 문법으로 명시

0으로 시작하는 숫자가 8진수라는 규칙은 우편번호나 앞자리 0이 있는 코드를 다룰 때 사고를 부릅니다.

7.  문 금지

with (Math) {
  console.log(PI);  // Math.PI? 아니면 외부 변수 PI?
}

with는 변수가 어느 스코프에 속하는지 런타임에야 알 수 있게 만듭니다. 가독성도 최악이고 엔진 최적화도 불가능해서 엄격 모드에서는 SyntaxError입니다.

8. 이 스코프를 오염시키지 않음

"use strict";
eval("var secret = 42;");
console.log(secret);  // ReferenceError

엄격 모드의 eval은 자체 스코프에서 실행되어, 바깥 스코프에 변수를 주입하지 못합니다.

9. 미래 예약어 보호

implements, interface, let, package, private, protected, public, static, yield — 이 단어들은 엄격 모드에서 식별자로 쓸 수 없습니다.

10. 함수 선언의 블록 스코프화

느슨한 모드에서 블록 안 함수 선언은 엔진마다 처리가 달랐습니다. 엄격 모드에서는 그 블록 안으로 스코프가 제한됩니다.

"use strict";
{
  function hello() { return "hi"; }
}
hello();  // ReferenceError

 

이미 자동으로 켜져 있는 곳들

여기가 핵심입니다. 모던 자바스크립트를 쓰고 있다면 이미 엄격 모드일 가능성이 높습니다.
ES 모듈은 항상 엄격 모드입니다.

// import/export를 쓰는 파일, <script type="module">,
// .mjs 파일, Node의 "type": "module" 패키지
// → "use strict" 없이도 전부 엄격 모드

클래스 본문도 항상 엄격 모드입니다.

class Foo {
  bar() {
    undeclared = 1;  // ReferenceError. 지시어 없어도.
  }
}

즉 React, Vue 같은 프레임워크로 개발하거나 번들러를 쓰고 있다면 대부분 이미 적용되어 있습니다. 이런 환경에서 "use strict"를 추가하는 것은 무해하지만 중복입니다.

반대로 여전히 명시가 필요한 경우도 있습니다.

  • 브라우저에서 <script> (모듈이 아닌 일반 스크립트)
  • Node.js의 CommonJS 파일 (.cjs, 또는 "type": "module"이 없는 .js)
  • 빌드 도구 없이 작성하는 스크립트

 

주의할 함정: 파일 병합

과거에 자주 발생했던 문제입니다. 엄격 모드로 짠 파일과 아닌 파일을 하나로 합치면, 맨 앞 파일의 지시어가 전체를 지배하게 됩니다.

/* a.js */  "use strict";  ...
/* b.js */  undeclared = 1;  // 원래 잘 돌던 코드가 깨짐

그래서 전통적으로는 IIFE로 감싸 범위를 가두는 패턴을 썼습니다.

(function () {
  "use strict";
  // 이 안에서만 적용
})();

요즘 번들러는 모듈 경계를 알아서 관리하므로 이 걱정은 대부분 사라졌습니다.

 

정리

항목 느슨한 모드 엄격 모드
선언 없는 할당 전역 변수 생성 ReferenceError
불가능한 대입 조용히 무시 TypeError
일반 호출의 this 전역 객체 undefined
중복 매개변수 허용 SyntaxError
with 허용 SyntaxError
8진수 0755 허용 SyntaxError

엄격 모드는 새로운 기능을 주는 게 아니라 위험한 기능을 빼앗는 쪽입니다. 코드가 할 수 있는 일을 줄여서, 실수가 조용히 지나가지 못하게 만듭니다.

결론은 간단합니다. ES 모듈이나 클래스를 쓰고 있다면 신경 쓸 필요가 없습니다. 이미 켜져 있으니까요. 그 외의 환경에서 스크립트를 작성한다면 첫 줄에 "use strict";를 넣어두세요. 비용은 한 줄, 얻는 것은 오타 하나 때문에 세 시간 날리는 일을 피할 확률입니다.

반응형
Comments