Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

ECMAScript 5의 Strict Mode

언젠가 node.js 프로젝트 소스를 보다가 use strict라는 코드를 보았습니다. 처음 본 코드라서 이게 무슨 코드인가 찾아보다가 ECMAScript의 기능이라는 것을 알게 되었습니다. 이것저것 찾아봤는데 John Resig이 정리해 놓은 ECMAScript 5 Strict Mode, JSON, and More라는 글에 제일 잘 나와있더군요. 예제 코드등 John Resig의 문서에 기초하고 있지만 전체 번역문서는 아니니 원문을 참고하시면 좋을 것입니다.(글을 쓰고나서 pismute님이 John Resig의 글을 번역해 놓으신걸 알게 되었습니다. 원문보기 어려우신 분은 번역글을 참고해 주세요.)


Strict Mode
Strict Mode는 ECMAScript 5에 추가된 모드로 ECMAScript 3와 호환성 때문에 존재하지만 ECMAScript 5에서는 폐기된 기능들은 사용하지 못하도록 하는 모드입니다. 그래서 Strict Mode를 사용하면 안전하지 않은 동작을 수행했을 때 차단되거나 예외가 발생해서 더 안전한 스크립트를 작성할 수 있도록 도와줍니다. John Resig옹의 글에 따르자면 ECMAScript 5의 Strict Mode는 파이어폭스에서 제공하는 Strict Mode와는 다르다고 합니다.(파폭에 저런 모드가 있는줄도 몰랐;;) 파이어폭스는 단순히 좋은 프렉티스를 강제할 뿐이지만 ECMAScript 5의 Strict Mode는 잠재적인 오류를 막아주는 새로운 모드입니다. ECMAScript 5의 Sctict Mode에 대해서는 ECMA-264 Edition 5 명세의 부록 C(247페이지)에 자세히 나와 있습니다.


use strict
use strict는 Strict Mode를 사용하는 명령어입니다. 프로그램전체에서 사용하려면 스크립트 최상단에 다음과 같이 추가합니다.

"use strict";

use strict는 스크립트 전체가 아닌 함수나 특정 컨텍스트내에서만 사용할 수도 있습니다.

function imStrict(){
  "use strict";
  // ... your code ...
}


"use strict";로 Strict Mode를 킬 수 있지만 보는 봐와 같이 그냥 문자열일 뿐이고 Strict Mode를 위해서 새로운 문법을 추가하지 않았습니다. 이는 호환성에 아무런 문제가 없기 때문에 호환성 걱정없이 Strict Mode를 사용할 수 있고 구형브라우저에서는 단순 문자열이기 때문에 무시할 것입니다. 즉 Strict Mode는 지금 당장이라도 사용할 수 있는 기능입니다.

// Non-strict code...
(function(){
  "use strict";
  
  // Define your library strictly...
})();

// Non-strict code...


앞에서 보았듯이 특정 컨텍스트에서만 Strict Mode를 사용할 수 도 있기 때문에 자신이 작성한 코드에서만 Strict Mode를 킬 수 있고 다른 코드에는 영향을 주지 않습니다.


Strict Mode에서 달라지는 점
앞에서 얘기했듯이 Strict Mode에서는 잠재적인 오류를 막아주는 역할을 하고 ECMAScript에서 모호한 사용으로 개발자들이 실수하기 쉬운 문제들을 인터프리터차원에서 차단해 줍니다.

변수와 프로프티
정의되지 않은 변수에는 할당을 할 수 없습니다. 즉, foo = "bar";와 같이 사용하는 경우 실패합니다. ECMAScript 3의 경우 이와 같은 코드는 window.foo에 "bar"를 할당하지만 Strict Mode에서는 ReferenceError 예외가 발생합니다.

프로퍼티의 경우 writable 속성이 false인 프로퍼티에 값을 작성하거나 configurable 속성이 false인 프로퍼티를 지우거나 extensible 속성이 false인 객체에 프로퍼티를 추가하는 등의 시도를 하면 TypeError 오류가 발생합니다. Strict Mode가 아닌 경우 이러한 시도는 아무런 노티없이 실패합니다.

var foo = "test";
function test(){}
delete foo; // Error
delete test; // Error

function test2(arg) {
  delete arg; // Error
}



객체 리터럴에서 같은 프로퍼티를 두번이상 정의하면 SyntaxError 예외가 발생합니다.

// Error
{ foo: true, foo: false }



eval
eval 이라는 이름의 사용자체를 막고 SyntaxError를 발생시킵니다.

// All generate errors...
obj.eval = ...
obj.foo = eval;
var eval = ...;
for ( var eval in ... ) {}
function eval(){}
function test(eval){}
function(eval){}
new Function("eval")



또한 eval 함수를 사용해서 새로운 변수를 정의하는 것도 차단합니다.

eval("var a = false;");
print( typeof a ); // undefined 



함수
함수의 아규먼트가 담긴 변수인 arguments를 덮어쓰면 오류가 발생합니다.

arguments = [...]; // not allowed




파라미터에서 같은 이름의 파라미터를 정의하면 오류가 발생합니다.

function( foo, foo ) {}




arguments.callerarguments.callee에 접근하면 예외를 던지기 때문에 익명함수를 참조해야 한다면 이름을 지정해야 합니다.

setTimeout(function later(){
  // do stuff...
  setTimeout( later, 1000 );
}, 1000 );




다른 함수에 대한 argumentscaller 프로퍼티는 존재하지 않기 때문에 이 프로퍼티들을 정의하는 것이 금지하고 TypeError를 던집니다.

function test(){
  function inner(){
    // Don't exist, either
    test.arguments = ...; // Error
    inner.caller = ...; // Error
  }
}




null이나 undefined를 전역객체로 강제하는 경우 오류가 발생합니다.

(function(){ ... }).call( null ); // Exception




그 밖에...
with(){}문은 Strict Mode에서 제거되었습니다. 실제로도 문법오류라고 나오며 with문이 이해하기도 어렵고 잘못사용될 여지가 크기 때문입니다. "implements", "interface", "let", "package", "private", "protected", "public", "static", "yield"는 미래를 위한 예약어가 되었습니다. 또한 this가 참조하는 객체가 없는 경우 자동으로 전역객체로 바꾸지 않습니다.


function() {

  return this; // Window

}
function() {
  "use strict";
  return this; // undefined
}

추가로 kangax가 만든 Strict Mode테스트 페이지에서 더 확인할 수 있습니다. 그리고 use strict는 Node.js에서도 사용할 수 있습니다.
2012/08/15 23:46 2012/08/15 23:46