Post

[모던 자바스크립트 Deep Dive]20장 strict mode

20.1 strict mode란?

기존의 오류가 발생하기 쉬운 환경

1
2
3
4
5
6
function foo() {
  x = 10;
}
foo();

console.log(x); // 10
  1. 자바스크립트 엔진은 foo 함수의 스코프에서 x 변수의 선언을 검색
    1. 없음
  2. 자바스크립트 엔진은 foo 함수의 상위 스코프, 즉 전역 스코프에서 x 변수의 선언을 검색
    1. 없음
  3. 자바스크립트 엔진은 암묵적으로 전역 객체에 x 프로퍼티를 동적 생성
    1. 전역객체의 x 프로퍼티는 전역 변수처럼 사용 가능해짐

이러한 현상을 암묵적 전역이라 하며 이는 높은 확률로 오류를 발생시키는 원인이 된다.

strict mode

  • ES5부터 도입
  • 잠재적인 오류를 발생시키기 어려운 개발 환경
  • 자바스크립트 문법을 엄격히 적용해 오류를 발생시킬 것 같거나, 자바스크립트 엔진의 최적화 작업에 문제를 일으킬 것 같으면 명시적 에러를 발생
  • ES6에서 도입된 클래스와 모듈은 기본적으로 strict mode 적용

린트 도구

  • 정적 분석 기능을 통해 소스코트를 스캔하여 오류를 찾아내 이를 리포팅해주는 도구
  • ESLint같은 린트 도구를 사용하면 strict mode와 유사한 효과를 얻을 수 있지만 린트 도구는 코딩 컨벤션까지 강제할 수 있다.

20.2 strict mode의 적용

  • 전역의 선두 또는 함수 몸체의 선두에 ‘use strict’;를 추가해 적용할 수 있다.

    1
    2
    3
    4
    5
    6
    
      'use strict';
        
      function foo() {
        x = 10; // ReferenceError: x is not defined
      }
      foo();
    
  • 함수 몸체의 선두에 추가하면 중첩 함수까지도 strict mode가 적용된다.
  • 코드 선두에 추가하지 않으면 제대로 동작하지 않는다.

    1
    2
    3
    4
    5
    
      function foo() {
        x = 10; // 에러를 발생시키지 않는다.
        'use strict';
      }
      foo();
    

20.3 전역에 strict mode를 적용하는 것은 피하자

  • 전역에 적용한 strict mode는 스크립트 단위로 적용된다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
      <!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 스크립트와 non-strict mode 스크립트를 혼용하는 건 오류 발생 확률을 높인다.
  • 따라서 즉시 실행 함수를 사용해 스코프를 구분하고 함수 선두에 strict mode를 적용하는 것을 권장한다.

    1
    2
    3
    4
    5
    6
    
      // 즉시 실행 함수의 선두에 strict mode 적용
      (function () {
        'use strict';
        
        // Do something...
      }());
    

20.4 함수 단위로 strict mode를 적용하는 것도 피하자

  • 어떤 함수에는 strict mode를 적용하고 어떤 함수는 적용하지 않는 것은 번거롭다.
  • 모든 함수에 strict mode를 적용하는 것은 번거롭다.
  • strict mode가 적용된 함수가 strict mode가 적용되지 않은 함수 외부 컨텍스트를 참조하면 문제가 발생할 수 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
      (function () {
        // non-strict mode
        var lеt = 10; // 에러가 발생하지 않는다.
        
        function foo() {
          'use strict';
        
          let = 20; // SyntaxError: Unexpected strict mode reserved word
        }
        foo();
      }());
    
  • 따라서 strict mode는 즉시 실행 함수로 감싼 스크립트 단위로 적용하는 게 바람직하다.

20.5 strict mode가 발생시키는 에러

20.5.1 암묵적 전역

1
2
3
4
5
6
(function () {
  'use strict';

  x = 1;
  console.log(x); // ReferenceError: x is not defined
}());
  • 선언하지 않은 변수를 참조하면 ReferenceError 발생

20.5.2 변수, 함수, 매개변수의 삭제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(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.
}());
  • delete 연산자로 변수, 함수, 매개변수를 삭제하면 SyntaxError 발생

20.5.3 매개변수 이름의 중복

1
2
3
4
5
6
7
8
9
(function () {
  'use strict';

  //SyntaxError: Duplicate parameter name not allowed in this context
  function foo(x, x) {
    return x + x;
  }
  console.log(foo(1, 2));
}());
  • 중복된 매개변수 이름을 사용하면 SyntaxError 발생

20.5.4 with문의 사용

1
2
3
4
5
6
7
8
(function () {
  'use strict';

  // SyntaxError: Strict mode code may not include a with statement
  with({ x: 1 }) {
    console.log(x);
  }
}());
  • with문을 사용하면 SyntaxError 발생
  • with
    • 전달된 객체를 스코프 체인에 추가
    • 동일한 객체의 프로퍼티를 반복해 사용할 때 객체 이름을 생략할 수 있어 코드를 줄임
    • 성능과 가독성이 나빠지므로 사용을 권장하지 않음

20.6 strict mode 적용에 의한 변화

20.6.1 일반 함수의 this

1
2
3
4
5
6
7
8
9
10
11
12
13
(function () {
  'use strict';

  function foo() {
    console.log(this); // undefined
  }
  foo();

  function Foo() {
    console.log(this); // Foo
  }
  new Foo();
}());
  • strict mode에서 함수를 일반 함수로 호출하면 thisundefined를 바인딩
  • 생성자 함수가 아닌 일반 함수 내부에선 this를 사용할 일이 없기 때문
    • 사용한다고 해도 에러는 발생하지 않는다.

20.6.2 arguments 객체

1
2
3
4
5
6
7
8
(function (a) {
  'use strict';
  // 매개변수에 전달된 인수를 재할당하여 변경
  a = 2;

  // 변경된 인수가 arguments 객체에 반영되지 않는다.
  console.log(arguments); // { 0: 1, length: 1 }
}(1));
  • strict mode에서 매개변수에 전달된 인수를 재할당해 변경해도 arguments 객체에 반영되지 않음
This post is licensed under CC BY 4.0 by the author.