| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | ||||||
| 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 | 20 | 21 | 22 |
| 23 | 24 | 25 | 26 | 27 | 28 | 29 |
| 30 | 31 |
- input
- HashMap
- CSS
- javascript
- html
- math
- 테스트자동화
- Java
- 단위테스트
- string
- 배열
- list
- java테스트
- ArrayList
- 인텔리제이
- 자바
- junit5
- 자바문법
- 자바스크립트
- Array
- Visual Studio Code
- 정규식
- junit
- vscode
- SpringBoot
- js
- 문자열
- Eclipse
- 스프링부트
- IntelliJ
- Today
- Total
어제 오늘 내일
[Javascript] "use strict"란? — 자바스크립트 엄격 모드 완전 정리 본문
자바스크립트 코드를 읽다 보면 파일 맨 위에 덩그러니 놓인 이 한 줄을 종종 만나게 됩니다.
"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느슨한 모드에서는 this가 undefined나 null이면 전역 객체로 자동 치환됩니다. 이걸 "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는 서로 살아있는 연결을 유지합니다. 하나를 바꾸면 다른 쪽도 바뀝니다. 직관에 어긋나고 최적화도 방해하므로 엄격 모드에서는 끊어집니다.
또한 arguments와 eval에 대입하는 것 자체가 금지됩니다.
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";를 넣어두세요. 비용은 한 줄, 얻는 것은 오타 하나 때문에 세 시간 날리는 일을 피할 확률입니다.
'IT > Javascript' 카테고리의 다른 글
| [JavaScript] 클로저(Closure) 완벽 가이드: 동작 원리부터 실전 패턴까지 (1) | 2026.08.08 |
|---|---|
| JavaScript Object.freeze 총정리: 얕은 동결의 함정과 deepFreeze 구현법 (1) | 2026.08.08 |
| JavaScript 비동기 처리 완전 정복: async/await 사용법 (0) | 2026.08.03 |
| [Javascript] HTML에서 외부 js 파일의 함수 호출하기 (0) | 2025.02.27 |
| [Javascript] 삼항연산자 사용법 및 활용 예제, 중첩 삼항연산자 (0) | 2025.02.26 |