Javascript – 현대 모드 “use strict”

오랜 기간동안 Javascript는 호환성 문제 없이 진화하고 있었습니다. 새로운 기능은 언어에 추가되어갔지만 이전의 기능들은 변화가 없었습니다. 그것은 기존의 코드들의 동작을 깨뜨리지 않는다는 장점이 있었습니다. 하지만 Javascript 제작자가 저지른 실수나 불완전한 결정이 언어에 영원히 머무르게 되었다는 단점이 있습니다.

이러한 단점은 2009년에 ECMAScript 5 (ES5)가 등장할 때 까지 존재하였습니다. 여기에는 언어에 새로운 기능이 추가되고 기존 기능 중 일부가 수정되었습니다. 기존의 오래된 코드들이 동작하도록 하기 위해 이러한 수정 사항은 기본적으로 해제되어있습니다. 이것을 활성화 하기 위해서는 “use strict”를 사용하여 명시적으로 활성화 하여야 합니다.

“use strict”

이 지시자는 “use strict” 또는 ‘use strict’ 라는 문자열로 표현됩니다. 이것이 스크립트의 최상단에 위치하게 되면 모든 스크립트는 “현대적인” 방법으로 동작하게 됩니다. 예를 들면 다음과 같습니다.

"use strict";

// this code works the modern way
...

이러한 지시자는 스크립트의 시작 지점이 아니라 함수의 시작 지점에도 넣을 수 있습니다. 이렇게 할 경우 스크립트 전체가 아닌 해당 함수에만 엄격(Strict) 모드가 적용 됩니다. 하지만 일반적으로 사람들은 모든 스크립트에 적용되도록 사용합니다.

(주의) “use strict”는 최상단에 위치해야 합니다.

항상 “use strict”는 스크립트의 최상단에 위치하도록 해주십시오, 그 외의 경우에는 엄격 모드(Strict Mode)가 활성화 되지 않습니다. 다음은 엄격 모드가 활성화 되지 않는 예시입니다.

alert("some code");
// 아래에 있는 "use strict"는 무시됩니다. 최상단에 선언 되어야 합니다.

"use strict";

// 엄격 모드 (Strict Mode)는 활성화되지 않습니다.

(주의) use strict를 취소할 수 있는 방법은 없습니다.

“no use strict” 와 같은 혹은 비슷한 지시자는 존재하지 않습니다. 한번 엄격 모드가 활성화 되면 그것을 돌이킬 수는 없습니다.

항상 “use strict”를 사용합시다.

“use strict” 와 “default/sloppy” 모드의 차이점에 대해서 알아 볼 필요가 있습니다. 가령 다음과 같은 차이를 발견할 수 있습니다.

1) 일반적으로 어떠한 변수를 사용하기 위해서는 그것을 먼저 선언할 필요가 있습니다. 하지만 과거의 자바스크립트에서는 let 또는 var 없이도 값을 할당하는것만으로도 변수를 선언하는 것이 가능했습니다. 심지어 요즘의 자바스크립트에서도 “use strict” 없이는 여전히 가능합니다. 이러한 동작은 과거의 스크립트와의 호환성을 위한 모습입니다.

// "use strict" 를 사용하지 않은 예제입니다.

num = 5; // 변수 "num"은 존재하지 않음에도 생성됩니다.

alert(num); // 5

이것은 굉장히 나쁜 사용 예이며 엄격 모드(Strict Mode)에서는 오류를 발생하게 됩니다.

"use strict";

num = 5; // 에러: num is not defined

2) 또한 엄격 모드에서는 값의 할당에 대해 발생할 수 있는 오류들을 잡아주는 역할을 합니다.

"use strict";

// 쓰기 금지된 프로퍼티에 값 쓰기 시도
var obj1 = {};
Object.defineProperty(obj1, "x", { value: 42, writable: false });
obj1.x = 9; // throws a TypeError

// Getter 밖에 없는 변수에 대한 값 할당 시도
var obj2 = { get x() { return 17; } };
obj2.x = 5; // throws a TypeError

// 확장 불가능한 객체에 대한 새로운 값 할당 시도
var fixed = {};
Object.preventExtensions(fixed);
fixed.newProp = "ohai"; // throws a TypeError

3) 엄격 모드에서는 삭제 불가능한 프로퍼티를 삭제하려고 시도할 경우 오류를 발생시킵니다. 이전에는 아무런 효과가 없던 코드입니다.

'use strict';
delete Object.prototype; // throws a TypeError

4) Gecko 34 버전 이전 브라우저들의 엄격 모드에서는 오브젝트의 모든 프로퍼티 이름은 고유해야 했습니다. 일반적인 코드에서 프로퍼티의 이름이 중복될 경우 마지막에서 할당한 값이 최종 값으로 결정되도록 하였습니다. 만약 마지막 값을 수정해야 하는데 실수로 그 이전 (중복된 이름의) 프로퍼티 값을 수정할 경우 정상적으로 적용이 안될 수 있으며 이는 엄격 모드에서 오류를 발생하게 변경되었습니다. (하지만 ECMAScript 2015에서 오류를 발생하지 않는것으로 원복되었습니다)

'use strict';
var o = { p: 1, p: 2 }; // !!! syntax error

5) 엄격 모드에서는 함수의 파라미터 이름이 고유해야 합니다. 보통의 코드들에서는 파라미터명이 중복될 경우 마지막 파라미터의 존재가 동일한 이름을 가진 이전 파라미터를 감추게 됩니다. 이 감춰진 파라미터는 arguments[i]로 접근할 수 있으므로 완벽하게 감추어진것도 아닙니다. 이는 의도적으로 감추고자 하더라도 완벽하게 수행될 수 없으므로 옳은 방법이 아닙니다. 그러므로 엄격 모드에서는 파라미터 명이 중복 될 경우 문법 오류가 발생합니다.

function sum(a, a, c) { // !!! syntax error
  'use strict';
  return a + a + c; // 만약 이 코드가 실행된다면 잘못된 동작을 하게 됨
}

6) ECMAScript 5의 엄격 모드에서는 8진 표현법의 사용을 금지합니다. 8진 표기법은 ECMAScript 5의 일부인것은 아니지만 모든 브라우저에서 앞에 0을 붙임으로써 표현이 가능합니다. (예: 0644 === 420 및 “\045” === “%”) ECMAScript 5에서의 8진 표기는 앞에 “0o”를 붙임으로써 지원 가능합니다.

var a = 0o10; // ES2015: Octal

초보 개발자들은 때때로 앞자리에 0을 붙이는 것이 특별한 의미가 없다고 생각하여 코드상의 정렬들 미관을 위해 사용합니다. 하지만! 값의 의미가 변경되게 됩니다. 앞자리에 0를 붙여 8진수로 만드는 것은 흔한 경우는 아니며 실수를 유발할 가능성이 더 크므로 엄격 모드에서는 오류를 발생시킵니다.

'use strict';
var sum = 015 + // !!! syntax error
          197 +
          142;

var sumWithOctal = 0o10 + 8;
console.log(sumWithOctal); // 16

7) ECMASCript 5의 엄격 모드에서는 원시 타입의 변수에 프로퍼티를 추가하는것을 허용하지 않습니다. 엄격 모드가 비활성화 상태일 경우 이러한 코드는 단순히 무시됩니다. 하지만 엄격 모드에서는 TypeError를 발생시킵니다.

(function() {
'use strict';

false.true = '';         // TypeError
(14).sailing = 'home';     // TypeError
'with'.you = 'far away'; // TypeError

})();

참고 :

  1. https://javascript.info/strict-mode
  2. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode