이 내용은 '모던 Javascript Deep Dive'(이웅모 님) 책의 내용을 제 생각과 함께 정리한 글입니다.
틀린 내용 혹은 수정이 필요한 내용이 있다면 말씀해주시면 감사하겠습니다.
function foo() {
x = 10;
}
foo();
console.log(x); // ?
일단 글을 쓰고 있는 나는 답을 '참조에러'라고 생각했다. 다들 비슷할 것이다. 이유는 var, let, const 키워드로 선언을 하지 않았기 때문이다.
그러나 JS 엔진이 전역 스코프까지 탐색했을 때, 암묵적으로 전역 객체에 x 프로퍼티를 동적 생성한다. 이 때, 전역 객체의 x 프로퍼티는 마치 전역 변수처럼 사용할 수 있다.
이러한 현상을 '암묵적 전역' 이라 한다.
개발자의 의도와는 상관없이 발생하는 암묵적 전역은 오류를 발생시키기 쉽다. 따라서 var, let, const로 선언을 하고 사용하자.
하지만 이런 오타나 문법 지식의 미비로 인한 실수는 언제든지 발생할 수 있다. 따라서 이러한 오류를 발생시키기 어려운 개발 환경을 만들고 그 환경에서 개발하는 것이 좀 더 근본적인 해결책이라고 볼 수 있다.
이에 따라 나온 것이 strict mode이고, ESLint도 이와 유사한 효과를 얻을 수 있다.
린트 도구는 오류는 물론 코딩 컨벤션을 설정 파일 형태로 정의하고 강제할 수 있기 때문에 더욱 효과가 좋다. (따라서 저자분께서는 린트 도구의 사용을 추천하시네요)
참고로 ES6에서 도입된 클래스와 모듈은 기본적으로 strict mode가 적용된다.
'use strict' 문구를 사용하면 된다.'use strict';
function foo() {
x = 10; // ReferenceError: x is not defined
}
foo();
function foo() {
'use strict';
x = 10; // ReferenceError: x is not defined
}
foo();
function foo() {
x = 10; // 에러를 발생시키지 않는다.
'use strict';
}
foo();
<!DOCTYPE html>
<html>
<body>
<script>
'use strict';
</script>
<script>
x = 1; // 에러가 발생하지 않는다.
console.log(x); // 1
</script>
<script>
'use strict';
y = 1; // ReferenceError: y is not defined
console.log(y);
</script>
</body>
</html>
번거로운 일이다. 또한 strict mode가 적용된 함수가 참조할 함수 외부의 컨텍스트에 strict mode를 적용하지 않는다면 이 또한 문제가 발생할 수 있다.
따라서 strict mode는 즉시 실행 함수로 감싼 스크립트 단위로 적용하는 것이 바람직하다.
(function () {
'use strict';
x = 1;
console.log(x); // ReferenceError: x is not defined
}());
delete 연산자로 변수, 함수, 매개변수를 삭제하면 SyntaxError가 발생한다.(function () {
'use strict';
var x = 1;
delete x;
// SyntaxError: Delete of an unqualified identifier in strict mode.
function foo(a) {
delete a;
// SyntaxError: Delete of an unqualified identifier in strict mode.
}
delete foo;
// SyntaxError: Delete of an unqualified identifier in strict mode.
}());
(function () {
'use strict';
//SyntaxError: Duplicate parameter name not allowed in this context
function foo(x, x) {
return x + x;
}
console.log(foo(1, 2));
}());
with문의 사용 - 이 부분은 p.318을 참조하자.thisstrict mode에서 함수를 일반 함수로서 호출하면
this에undefined가 바인딩된다.
생성자 함수가 아닌 일반 함수내부에서는this를 사용할 필요가 없기 때문이다.
(function () {
'use strict';
function foo() {
console.log(this); // undefined
}
foo();
function Foo() {
console.log(this); // Foo
}
new Foo();
}());
arguments 객체arguments 객체에 반영되지 않는다.(function (a) {
'use strict';
// 매개변수에 전달된 인수를 재할당하여 변경
a = 2;
// 변경된 인수가 arguments 객체에 반영되지 않는다.
console.log(arguments); // { 0: 1, length: 1 }
}(1));