|
| 1 | +ES5 표준까지해도 자바스크립트는 문제가 많았습니다. 그러나 이 시기에도 완성도 높은 프로그래밍을 위해 여러 방법을 강구했죠. 그 중 하나인 엄격(strict) 모드에 대해 알아봅니다. |
| 2 | + |
| 3 | +## strict mode |
| 4 | +> 자바스크립트 언어의 문법을 좀 더 엄격히 적용해 문제를 내포하는 코드에 대해 명시적 에러를 발생시킵니다. |
| 5 | +
|
| 6 | +다시 한 번 생각해봅시다. 자바스크립트 언어의 문제점은 뭐가 있었을까요? 대표적으로 꼽자면 var 키워드, 변수 호이스팅, 암묵적 전역(Implict global) 등이 있었죠. 암묵적 전역에 대해 코드를 살펴보고 빠르게 넘어가겠습니다. |
| 7 | + |
| 8 | +- 암묵적 전역 : 아무리 봐도 에러인 아래의 코드는 너무나 잘 작동됩니다. |
| 9 | + ```js |
| 10 | + function foo() { |
| 11 | + x = 10; |
| 12 | + } |
| 13 | + foo(); |
| 14 | + |
| 15 | + console.log(x); // 10 |
| 16 | + ``` |
| 17 | + - 코드의 문제를 이해하기 위해 자바스크립트 엔진의 동작 순서를 살펴볼까요 |
| 18 | + 1. foo 함수 내에서 선언하지 않은 x 변수에 값 10을 할당합니다. |
| 19 | + 2. x 변수가 어디에서 선언되었는지 스코프 체인을 통해 검색합니다. |
| 20 | + 3. foo 스코프에서 탐색하고, 상위 스코프인 전역 스코프에서 x 변수의 선언을 탐색합니다. |
| 21 | + 4. 그 어디에도 존재하지 않아 ReferenceError를 발생시켜야하나 엔진은 동적으로 x 프로퍼티를 생성합니다. |
| 22 | + 5. 전역 객체의 x 프로퍼티는 전역 변수처럼 사용할 수 있게 됩니다. 이러한 현상이 **암묵적 전역**입니다. |
| 23 | + |
| 24 | +이 외에도 많은 문제로 인해 ES5에서 strict mode(엄격 모드)가 추가 되었으며, ESLint 같은 린트 도구로도 이를 강력하게 검사할 수 있습니다. |
| 25 | + |
| 26 | +<br> |
| 27 | + |
| 28 | +## strict mode 적용하기 |
| 29 | +> 전역의 선두 또는 함수 몸체 선두에 `'use strict';`를 작성합니다. |
| 30 | +
|
| 31 | +- 전역의 선두에 작성 시 전역 스코프에 적용됩니다. |
| 32 | + ```js |
| 33 | + 'use strict'; |
| 34 | + |
| 35 | + function foo(){ |
| 36 | + x = 10; // ReferenceError: x is not defined |
| 37 | + } |
| 38 | + foo(); |
| 39 | + ``` |
| 40 | + |
| 41 | +- 함수 몸체의 선두에 작성 시 해당 함수 스코프에서만 적용됩니다. |
| 42 | + ```js |
| 43 | + function foo(){ |
| 44 | + 'use strict'; |
| 45 | + x = 10; // ReferenceError: x is not defined |
| 46 | + } |
| 47 | + foo(); |
| 48 | + ``` |
| 49 | + |
| 50 | +- 선두가 아닌 곳에 작성 시제대로 동작하지 않습니다. |
| 51 | + ```js |
| 52 | + function foo(){ |
| 53 | + x = 10; |
| 54 | + 'use strict'; |
| 55 | + } |
| 56 | + foo(); |
| 57 | + ``` |
| 58 | + |
| 59 | +<br> |
| 60 | + |
| 61 | +## 주의사항 |
| 62 | +### 전역에 적용하는 것은 피하기 |
| 63 | +> 전역에 적용한 strict mode는 스크립트 단위로 적용됩니다. |
| 64 | +
|
| 65 | +- 다른 스크립트에 영향을 주지 않고 해당 스크립트에 한정됩니다. |
| 66 | + ```html |
| 67 | + <!DOCTYPE html> |
| 68 | + <html lang="en"> |
| 69 | + |
| 70 | + <head> |
| 71 | + <meta charset="UTF-8"> |
| 72 | + <meta http-equiv="X-UA-Compatible" content="IE=edge"> |
| 73 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| 74 | + <title>Document</title> |
| 75 | + </head> |
| 76 | + |
| 77 | + <body> |
| 78 | + <script type="text/javascript"> |
| 79 | + 'user strict'; |
| 80 | + </script> |
| 81 | + <script type="text/javascript"> |
| 82 | + x = 1; |
| 83 | + console.log(x); |
| 84 | + </script> |
| 85 | + <script type="text/javascript"> |
| 86 | + 'user strict'; |
| 87 | +
|
| 88 | + y = 1; |
| 89 | + console.log(y); // ReferenceError: y is not defined |
| 90 | + </script> |
| 91 | + </body> |
| 92 | + |
| 93 | + </html> |
| 94 | + ``` |
| 95 | + - 스크립트 별로 적용하는 것은 오류를 발생시킬 수 있습니다. 특히 외부 라이브러리를 사용할 때는요. |
| 96 | + |
| 97 | +<br> |
| 98 | + |
| 99 | +### 함수 단위로 적용하는 것은 피하기 |
| 100 | +> 어떤 함수는 strict mode, 어떤 함수는 non-strict mode? 당연히 바람직하지 않으며, 그런다고 모든 함수에 일일이 strict mode를 적용하는 것도 옳지 않습니다. |
| 101 | +
|
| 102 | +- strict mode가 적용된 함수가 참조할 함수 외부의 컨텍스트에 strict mode를 적용하지 않았다면 문제가 발생할 수 있습니다. |
| 103 | + ```js |
| 104 | + (function(){ |
| 105 | + var x = 10; |
| 106 | + |
| 107 | + function foo(){ |
| 108 | + 'use strict'; |
| 109 | + |
| 110 | + x = 20; |
| 111 | + } |
| 112 | + foo(); |
| 113 | + }()); |
| 114 | + ``` |
| 115 | + - `에러가 난다고 적혀있는데 정상적으로 작동하네요?🙄 무슨 일이지...` |
| 116 | + |
| 117 | +그럼 strict mode로 코드를 엄격하게 관리해서 일어나는 일은 뭐가 있을까요? |
| 118 | + |
| 119 | +<br> |
| 120 | + |
| 121 | +## strict mode가 발생시키는 에러 |
| 122 | +> 암묵적 전역, 변수/함수/매개변수의 삭제, 매개변수 이름 중복, with문 사용 등이 대표적입니다. |
| 123 | +
|
| 124 | +### 암묵적 전역 |
| 125 | +> 선언하지 않은 변수를 참조하면 ReferenceError가 발생합니다. |
| 126 | +
|
| 127 | +```js |
| 128 | +(function(){ |
| 129 | + 'use strict'; |
| 130 | + x = 10; |
| 131 | + console.log(x); // ReferenceError: x is not defined |
| 132 | +}()); |
| 133 | +``` |
| 134 | + |
| 135 | +<br> |
| 136 | + |
| 137 | +### 변수/함수/매개변수의 삭제 |
| 138 | +> delete 연산자로 해당 프로퍼티를 삭제하면 SyntaxError가 발생합니다. |
| 139 | +
|
| 140 | +```js |
| 141 | +(function(){ |
| 142 | + 'use strict'; |
| 143 | + var x = 10; |
| 144 | + |
| 145 | + delete x; // SyntaxError: Delete of an unqualified identifier in strict mode. |
| 146 | + |
| 147 | + function foo(a) { |
| 148 | + delete a; // SyntaxError: Delete of an unqualified identifier in strict mode. |
| 149 | + } |
| 150 | + |
| 151 | + delete foo; // SyntaxError: Delete of an unqualified identifier in strict mode. |
| 152 | +}()); |
| 153 | +``` |
| 154 | + |
| 155 | +<br> |
| 156 | + |
| 157 | +### 매개변수 이름 중복 |
| 158 | +> 중복된 이름을 사용하면 SytaxError가 발생합니다. |
| 159 | +
|
| 160 | +```js |
| 161 | +(function(){ |
| 162 | + 'use strict'; |
| 163 | + |
| 164 | + function foo(a, a) { |
| 165 | + return a + a; // SyntaxError: Duplicate parameter name not allowed in this context |
| 166 | + } |
| 167 | + |
| 168 | + console.log(foo(1, 2)); |
| 169 | +}()); |
| 170 | +``` |
| 171 | + |
| 172 | +<br> |
| 173 | + |
| 174 | +### with문 사용 |
| 175 | +> 전달된 객체를 스코프 체인에 추가하는 with문을 사용하면 SyntaxError가 발생합니다. |
| 176 | +
|
| 177 | +```js |
| 178 | +(function(){ |
| 179 | + 'use strict'; |
| 180 | + |
| 181 | + with({ x: 1 }){ |
| 182 | + console.log(x); // SyntaxError: Strict mode code may not include a with statement |
| 183 | + } |
| 184 | +}()); |
| 185 | +``` |
| 186 | + |
| 187 | +마지막입니다! strict mode를 적용하면 변하는 동작이 존재할까요? 그 답은 `있습니다`이고, 이제 확인해 볼 거에요. |
| 188 | + |
| 189 | +<br> |
| 190 | + |
| 191 | +## strict mode 적용에 의한 변화 |
| 192 | +> 일반 함수의 this와 arguments 객체의 동작이 변경됩니다. |
| 193 | +
|
| 194 | +### 일반 함수의 this |
| 195 | +> 일반 함수로 호출하면 this에 undefined가 바인딩됩니다. 생성자 함수가 아닌 일반 함수 내부에서는 this를 사용할 필요가 없기 때문이죠. |
| 196 | +
|
| 197 | +```js |
| 198 | +(function(){ |
| 199 | + 'use strict'; |
| 200 | + |
| 201 | + function foo(){ |
| 202 | + console.log(this); // undefined |
| 203 | + } |
| 204 | + foo(); |
| 205 | + |
| 206 | + function Foo(){ |
| 207 | + console.log(this); // Foo |
| 208 | + } |
| 209 | + new Foo(); |
| 210 | +}()); |
| 211 | +``` |
| 212 | + |
| 213 | +<br> |
| 214 | + |
| 215 | +### arguments 객체 |
| 216 | +> 매개변수에 전달된 인수를 재할당하여 변경해도 반영되지 않습니다. |
| 217 | +
|
| 218 | +```js |
| 219 | +(function(x){ |
| 220 | + 'use strict'; |
| 221 | + |
| 222 | + x = 10; |
| 223 | + console.log(arguments); // Arguments [callee: (...), Symbol(Symbol.iterator): ƒ] |
| 224 | +}()); |
| 225 | +``` |
| 226 | + |
| 227 | +<hr> |
| 228 | +<br> |
0 commit comments