티스토리 뷰

공부를 시작하며

"use strict"; 가 엄격 모드를 사용한다! 라는 정도로만 알고 있고, 이 모드를 사용함으로써 정확하게 동작하는것이 무엇인지 알지 못했습니다. 이 공부를 통해서 strict mode 가 어떠한 특징을 가지고 있는지를 배워갑니다.

공부는 책 모던 자바스크립트 Deep Dive를 통해 진행하였습니다.

 

strict mode

strict mode, 엄격 모드는 자바스크립트 언어의 문법을 엄격하게 적용시켜 오류가 발생할 가능성이 높거나 자바스크립트 엔진의 최적화 작업에 문제를 일으킬 수 있는 코드에 명시적인 에러를 발생시킵니다.

 

다음의 예제를 통해서 이 부분에 대해서 설명하겠습니다.

function foo() {
  x = 1;
}

foo();

console.log(x);

위의 예제에서 console.log를 통해 x를 출력하게되면 값은 무엇이 나오게 될까요?

값은 1이 출력이 되게됩니다. 하지만 이 점은 오류가 날 가능성이 높은 코드입니다.

변수 선언문을 통해서 선언하지 않은 변수같은 경우엔 암묵적으로 전역 객체에 해당 프로퍼티를 생성합니다.

전역적으로 접근이 가능해졌으니 해당 값은 1이 출력이 되게 되는것이죠.

위의 내용은 이 글을 통해 확인 가능합니다.

 

위와 같은 위험한 상황을 피하고 안전한 코딩을 하기 위해서는 변수의 선언문을 통해서 변수를 선언해주어야합니다.

단편적으로 위의 코드는 길지 않고 명확하게 확인이 가능했지만, 확인하기 어려운 위치와 에러를 발생 시켜주지 않아 대비하기 어려워보입니다.

이때에 사용할 수 있는 방법이 strict mode를 사용하는 것입니다.

 

strict mode 적용

strict mode를 적용하려면 전역의 선두 또는 함수의 선두에 "use strict"; 를 추가해줍니다.

 

위의 예제에 상단에 "use strict"를 작성해봅니다.

이전과는 달리 console.log를 통해 x를 출력해보면 ReferenceError 에러가 발생합니다.

"use strict";
function foo() {
  x = 1;
}

foo();

console.log(x);
// Uncaught ReferenceError: x is not defined at foo

 

 

 

함수의 선두

아래는 함수의 몸체의 선두에 strict mode를 적용 해주었습니다.

이렇게 작성하면 해당 함수와 중첩 함수들에만 strict mode가 적용이됩니다.

function foo() {
  "use strict";
  x = 1;
}

foo();

console.log(x);
// Uncaught ReferenceError: x is not defined at foo

 

에러 발생 여지가 있는 코드의 다음에 작성할 때

아래는 문제의 변수 선언문이 없는 암묵적 전역 변수의 다음에 strict mode를 적용한 예시입니다.

이 경우에는 strict mode가 해당 코드에 적용이 되지 않습니다.

function foo() {
  x = 1;
  "use strict";
}

foo();

console.log(x);
// 출력 : 1

 

전역에 strict mode를 적용한다면

strict mode는 script 별로 적용이됩니다.

다음과 같이 HTML 파일에 두 script 태그가 있습니다.

<body>
  <script>
    "use strict";
  </script>
  <script>
    // strict mode가 적용되지 않습니다.
    strict = 1;
  </script>
</body>

첫번째 script 태그 내 적용된 strict mode가 두번째 script에는 적용이 되지 않습니다.

 

피해야할 strict mode 적용

전역에 strict mode를 적용하는것도 좋지 못한 선택이 될수도 있습니다.

외부 라이브러리를 사용하게되면 해당 라이브러리가 non-strict mode 즉 엄격모드가 아닌 경우에는 오류가 발생할 수 있습니다. 또한 strict mode와 non-strict mode를 혼용해서도 오류를 발생시킬 염려가 있습니다.

 

이런경우에는 스크립트의 전체를 즉시실행 함수 몸체 선두에 strict mode를 적용해서 해결하는 방법이 있습니다.

(function () {
  "use strict";
  let test = 1;
})();

// 라이브러리 코드
library = 1;
console.log(library);
// 출력 : 1 ( 오류가 발생하지 않습니다 )

 

위와 반대로 함수 단위로써 strict mode를 적용하는것은 바람직하지 않습니다.

하나하나 모든 함수에 strict mode를 적용하는것도 공수가 클 뿐더러 중첩 함수와 같은 경우에는 이 문제가 부각됩니다.

strict mode의 함수 단위별 사용은 스크립트 단위별로 즉시 실행 함수로 감싸는 정도의 사용으로 사용하는 것이 바람직합니다.

 

다음은 중첩 함수에서 발생할 수 있는 strict mode 적용 실수의 예제입니다.

즉시 실행 함수에서 strict mode가 적용이 안된 let의 이름으로 된 var 변수의 선언은 let이라는 이미 정의된 변수 선언문 키워드로써 네임을 사용할 수 없지만 에러가 발생하지 않습니다. 하지만 내부의 foo에서는 strict mode를 적용하고 let이라는 암묵적 전역변수를 선언했지만 strict mode에 의해서 syntaxError 에러가 발생하게 됩니다.

(function () {
  var let = 0;
  function foo() {
    "use strict";
    let = 10;
    // Uncaught SyntaxError: Unexpected strict mode reserved word
  }
  foo();
})();

 

strict mode로 발생되는 에러들

 

암묵적인 전역

위에서 다뤘던 strict mode를 사용하면 발생하는 에러 예시중 하나입니다.

선언하지 않은 변수를 참조하게되면 ReferenceError 가 발생합니다.

(function () {
  "use strict";
  
  x = 1;
  console.log(x);
  // Uncaught ReferenceError: x is not defined
})();

 

임의적으로 변수, 함수, 매개변수를 삭제했을때

delete 연산자를 통해서 변수, 함수, 매개변수를 삭제하면 syntaxError 에러가 발생합니다.

(function () {
  "use strict";

  var x = 1;
  // 변수의 삭제
  delete x;

  function foo(a) {
    // 매개변수의 삭제
    delete a;
  }

  // 함수의 삭제
  delete foo;

  // 위 delete 연산자를 통해 직면할 수 있는 에러는 다음과 같습니다.
  // Uncaught SyntaxError: Delete of an unqualified identifier in strict mode.
})();

 

매개변수 이름의 중복

다음과 같이 매개변수가 중복된 이름으로 사용되면 SyntaxError 에러가 발생합니다.

(function () {
  "use strict";

  function foo(x, x) {
    // Uncaught SyntaxError: Duplicate parameter name not allowed in this context
    return x + x;
  }
})();

 

+ with 문의 사용

with 문을 strict mode가 적용된 상태에서 사용하게되면 syntaxError가 발생합니다.

거의(?) 사용하지 않는 문법이기에 따로 설명글을 첨부하지 않겠습니다.

 

에러가 발생하지는 않는 strict mode

결과가 반영되지 않지만 에러가 발생하지 않는 상황들이 있습니다.

 

일반 함수에서의 this

strict mode가 적용된 일반 함수를 함수로 호출하면 this에는 undefined가 반환됩니다. 생성자 함수가아닌 일반 함수 내부에서는 this가 사용될 필요가 없다고 판단되기 때문인데요. 다음 예시는 일반 함수의 함수 호출, 생성자 함수의 new 를 통한 호출로 설명이 되고있습니다. 일반 함수를 호출할때 에러는 발생하지 않습니다.

(function () {
  "use strict";

  function person() {
    console.log(this);
    // 출력 : undefined
  }
  person();

  function Person() {
    console.log(this);
    // 출력 : Person {}
  }

  new Person();
})();

 

arguments 객체

strict mode에서는 매개변수에 전달된 인수를 다른 값으로 재할당해도 arguments 객체에 반영이 되지 않습니다.

하지만 이 경우에도 에러가 발생하지 않습니다. 다음 예시를 보면 x에 직접적으로 재할당 한 값은 할당한 값으로 출력이 되지만, arguments 객체의 값은 변경이 없는것을 확인할 수 있습니다.

(function () {
  "use strict";

  function foo(x) {
    x = 3;

    console.log(x);
    // 출력 : 3;
    console.log(arguments);
    // 출력 : { 0: 2,.... }
  }

  foo(2);
})();

 

정리해볼까요?

Q. strict mode란 무엇인가요?

A. strict mode란 엄격 모드로써 자바스크립트의 문법을 엄격하게 적용시켜 오류가 발생할 여지가 있는 코드에서 명시적인 에러가 발생할 수 있도록 해주는 모드입니다. 사용하는 방법은 전역 또는 함수 몸체의 선두에 "use strict"; 를 작성함으로써 strict mode를 적용해 볼 수 있습니다.

 

Q. strict mode를 사용함으로써 장/단점이 무엇이라고 생각하나요?

A. strict mode를 사용함으로써 암묵적 전역, 매개변수의 중복 등  실수해서 발생할 수 있는 에러들을 명시적으로 발생시켜서 사전에 에러를 방지할 수 있다는 장점이 있습니다. 하지만 strict mode를 사용하게되면 외부 라이브러리가 strict mode를 사용하지 않는 non-strict mode로 구동되게되면 strict mode와 non-strict mode의 혼용이 있을수 있어 오히려 이로 인해서 에러를 발생시킬 수 있는 가능성이 있습니다. 이 점을 방지하기 위해서는 strict mode를 함수 단위의 선두에 사용하면 되는데 중첩 함수를 통한 사용은 strict mode가 적용된 시점을 정확하게 파악하기 힘들 뿐더러 빈번하게 하나하나 적용을 해야하는 단점이 있어 script 단위의 즉시 실행함수로써 선두에 두어 사용하면 된다고 생각합니다.

 

 

출처

책 : 모던 자바스크립트 Deep Dive

댓글
최근에 올라온 글