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.caller와 arguments.callee에 접근하면 예외를 던지기 때문에 익명함수를 참조해야 한다면 이름을 지정해야 합니다.
setTimeout(function later(){
// do stuff...
setTimeout( later, 1000 );
}, 1000 );
다른 함수에 대한 arguments와 caller 프로퍼티는 존재하지 않기 때문에 이 프로퍼티들을 정의하는 것이 금지하고 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에서도 사용할 수 있습니다.
저도 신기했습니다. 문자열이 DTD처럼 실행되니까요.
아래 링크 이미지(크록포트 얼굴에 척노리스 몸체 ^^;)가 생각나서 댓글 답니다.
http://bodil.org/coffeescript/#strict-mode-slide
lint류나 커피만 쓰다가 이런게 있는지는 처음알았었요. ㅎㅎ
처음 봤을때 이코드는 머하는건가 싶었었죠 ㅎㅎ
크락포드님의 JSLint 돌리다보면 나오는 거라 뭔가 했는데 이런 의미였군요.
잘 배우고 갑니다!
검색하다보니 JSLint류나 JSHint류에 있는것 같더라구요..(관련 질문들이.. ㅎㅎ) 이런것들 쓰는것도 좀 습관들려야 하는데 잘 쓰진 않네요... 맘잡고 셋팅해서 써야겠어요 ㅋ
http://dogfeet.github.com/articles/2011/1317873491.html
오역이 있을지도 모르지만, 번역한 것도 있습니다.
아앗!!
내용이 거의 겹치는데 번역된 내용이 있는줄 몰랐네요 ㅠㅠ(본문에 추가해 넣어야겠어요.
저 중 일부는 가능했다는게 더 신기한 것도 있네요 ;;
인터프리터단에서 하는거지 못할 부분은 없지 않나요?
하긴 객체 리터럴에 프로퍼티를 중복 정의해도
사람 보기에 이상할 뿐이지 인터프리터한테는
별거 아니겠군요 :)
그쵸.. 어차피 인터프리터는 다 파싱해서 해석해야하니까 문법오류 체크하는거랑 크게 다를바는 없어보입니다. ㅎ
항상 좋은 내용 열심히 읽고 있습니다 ㅎ 감사합니다 ㅎ
잘 읽어주고 계시다니 감사합니다.