MDN’s new design is in Beta! A sneak peek: https://blog.mozilla.org/opendesign/mdns-new-design-beta/

Strict mode

현재 번역은 완벽하지 않습니다. 한국어로 문서 번역에 동참해주세요.

ECMAScript 5의 엄격모드는 JavaScript의 제한된 변형을 취사 선택하기 위한 방법입니다. 엄격 모드는 단지 부분적인 것이 아니며, 이것은 고의적으로 일반 코드와 다른 시멘틱을 가지고 있습니다. 엄격모드를 지원하지 않는 브라우저에서는 엄격 모드의 코드기 다른 방식으로 동작할 것입니다, 그 때문에 엄격 모드가 적절하게 적용된 피쳐 테스트 없이 엄격 모드에 의존하면 안됩니다. 엄격 모드의 코드와 비-엄격 모드의 코드는 공존할 수 있으며, 때문에 스크립트의 엄격 모드를 취사 선택하는 것이 점진적으로 가능하게 되었습니다.
 

엄격 모드는 평범한 JavaScript 시멘틱에 다양한 변화를 만듭니다. 먼저, 엄격 모드는 JavaScript 가 묵인했던 에러들을 에러를 던지게끔 변화를 주어 제거 합니다. 둘째로는, 엄격 모드는 JavaScript 엔진이 최적화 작업을 하는 데에 어렵게 만드는 실수들을 고칩니다. (가끔씩 엄격 모드의 코드는 비-엄격 모드의 동일한 코드보다 더 빨리 작동하도록 만들어집니다.) 세번째는, 엄격 모드는 ECMAScript의 차기 버전들에서 정의 될 문법을 금지합니다. 

코드를 JavaScript의 변형이 제한된 환경에서 동작하도록 하고 싶다면, 엄격 모드로의 변환(transitioning to strict mode)을 참고하세요.

가끔씩은 스탠다드, 즉 비-엄격모드를 "느슨한 모드(sloppy mode)"라고 부르는 것을 보게될 것입니다. 이 용어는 공식적이지는 않지만, 알고 계셔야 합니다. 만약의 경우를 대비해서요.

엄격모드 적용하기

엄격 모드는 전체 스크립트 또는 각각의 함수에 적용합니다. 이것은 {} 괄호로 묶여진 블럭문에는 적용되지 않습니다. 여기서 적용하도록 시도하는 것은 아무것도 하지 않습니다. eval 코드, 함수 코드, 이벤트 핸들러 속성, WindowTimers.setTimeout()에 넘겨진 문자열들 등이 전체 스크립트이며, 그 안에서 엄격 모드 적용은 예상대로 작동합니다. 

스크립트 엄격 모드

엄격모드를 전체 스크립트에 적용하기 위해, 정확한 구문 "use strict";(또는 'use strict';) 를 다른 구문 작성 전에 삽입합니다.

// Whole-script strict mode syntax
"use strict";
var v = "Hi!  I'm a strict mode script!";

이 구문은 이미 중요한 사이트를 가지고 있다. 그것은 non-conflicting 스크립트를 맹목적으로 조롱하는 것은 불가능하다.. (이 구문은 이미 유명한 웹사이트에서 문제를 일으킨 전적이 있습니다.) 상충되지 않는 스크립트들 끼리 맹목적인 연결이 불가능하기 때문입니다. 엄격 모드의 스크립트와 비-엄격 모드의 스크립트의 연결은 심사숙고 하시기를 바랍니다. 이렇게 되면 전체 연결은 엄격으로 보입니다! 이것의 역 또한 참입니다. 비-엄격과 엄격의 결합은 비-엄격입니다. 엄격 모드에 다른 것들을 결합하는 것은 괜찮습니다. 그리고, 비-엄격 스크립트와의 결합도 괜찮습니다. 다만, 엄격과 비-엄격의 결합만 문제가 있습니다. 그때문에 이는 함수에 의한 함수 기준에서의 엄격 모드가 가능하도록 권했습니다. (적어도 과도기에서만)

또한 함수 내부의 전체 스크립트 내용에 접근할 수 있으며, 엄격모드를 사용하는 외부 함수를 가질 수 있습니다. 이는 결합 문제를 없애주기도 하지만, 이것이 스코프 바깥에 위치한 어떤 전역 변수든 확실하게 밖으로 추출할 수 있음을 의미합니다 . 

Strict mode for functions

마찬가지로, 기능에 대한 엄격한 모드를 호출하려면, 정확한 진술을 하라."use strict"; (or 'use strict';) 다른 진술에 앞서.

function strict(){
  // Function-level strict mode syntax
  'use strict';
  function nested() { return "And so am I!"; }
  return "Hi!  I'm a strict mode function!  " + nested();
}
function notStrict() { return "I'm not strict."; }

엄격한 모드 변경

엄격한 모드는 구문과 런타임 동작을 모두 변경합니다.
일반적으로 이러한 카테고리에 변화가 발생합니다: 실수를 실수로 잘못 해석하거나(문법 오류 또는 런타임에 오류 발생), 특정 변수의 특정 변수에 대한 특정 변수를 계산하는 방법을 단순화하는 방법, 변화를 단순화하고 논쟁을 야기하는 변화를 단순화하고,"보안"자바 스크립트를 작성하고, 미래의 진화론적 진화를 기대하는 변화를 만들어 낸다.

실수를 에러로 바꾸는 것

엄격한 모드는 일부 오류를 오류로 바꿔 놓습니다.
자바 스크립트는 초보자 개발자에게 쉬운 것이 되도록 설계되었으며, 때로는 오류가 발생하는 의미가 있어야 한다.
때때로 이것은 즉각적인 문제를 해결하지만, 때때로 이것은 더 심각한 문제를 만들어 낸다.
엄격한 모드는 이러한 실수를 발견하고 즉시 수리할 수 있도록 오류를 처리합니다.

첫째로, 엄격한 모드는 실수로 글로벌 변수를 생성하는 것을 불가능하게 만든다.
일상적인 자바 스크립트에서 변수를 생성하면 새로운 속성이 생성되고,"mistyping"는 글로벌 객체에 대한 새로운 속성을 생성합니다(미래에는 가능한 실패 가능성이 있음).
실수로 인해 글로벌 변수가 아닌 글로벌 변수를 생성할 수 있습니다.

"use strict";
                       // Assuming a global variable mistypedVariable exists
mistypedVaraible = 17; // this line throws a ReferenceError due to the 
                       // misspelling of variable

둘째로, 엄격한 모드는 할당되지 않은 과제를 유발할 수 있는 과제를 만든다.
예를 들어, NaN은 0x non-writable 글로벌 변수입니다.
NaN에 할당된 정상 코드는 아무 것도 아닙니다. 개발자는 아무런 고장 피드백도 받지 않습니다.. INaN에 할당된 엄격한 모드로 예외가 throw 됩니다. 정상 코드에서 정상적으로 작동하지 않는 할당 (할당된 속성에 할당된 속성, 할당되지 않은 속성에 할당 할당, 새 속성에 대한 할당) will throw in strict mode:

"use strict";

// Assignment to a non-writable property
var obj1 = {};
Object.defineProperty(obj1, "x", { value: 42, writable: false });
obj1.x = 9; // throws a TypeError

// Assignment to a getter-only property
var obj2 = { get x() { return 17; } };
obj2.x = 5; // throws a TypeError

// Assignment to a new property on a non-extensible object
var fixed = {};
Object.preventExtensions(fixed);
fixed.newProp = "ohai"; // throws a TypeError

세번째로 엄격한 모드는 undeletable 속성을 삭제합니다(시도가 없는 경우).

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

네번째, 34번째로 엄격한 모드 이전의 엄격한 모드는 사물의 모든 속성이 독특하다는 것을 요구한다.
일반 코드는 속성의 값을 결정하는 마지막으로 속성 이름을 중복할 수 있습니다.
그러나 마지막으로, 마지막으로 하나의 것만 있다면, 복제는 단순히 마지막 인스턴스를 변경하는 것 이외의 속성 값을 변경하기 위해 수정된 코드를 변경하기 위한 매개 변수일 뿐이다.
중복된 속성 이름은 엄격한 모드에서 구문 오류입니다.

This is no longer the case in ECMAScript 6 (bug 1041128).

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

다섯번째, 엄격한 모드는 함수 매개 변수 이름이 고유함을 요구한다.
일반 코드에서 마지막으로 중복된 인수가 이전 버전 인수를 숨깁니다.
그 이전의 주장들은 충분히 이용 가능하므로, 그들은 완전히 접근할 수 없다.
그래도 이 숨김은 별 의미가 없고, 아마도 바람직하지 않을 것입니다.(예:오타를 숨길 수도 있습니다.)엄격한 모드 중복 논법은 구문론 오류입니다.

function sum(a, a, c){ // !!! syntax error
  "use strict";
  return a + b + c; // wrong if this code ran
}

Sixth, strict mode in ECMAScript 5 forbids octal syntax. Octal syntax isn't part of ECMAScript 5, but it's supported in all browsers by prefixing the octal number with a zero: 0644 === 420 and "\045" === "%". In ECMAScript 6 Octal number is supported by prefixing a number with "0o". i.e. 

var a = 0o10; // ES6: Octal

Novice developers sometimes believe a leading zero prefix has no semantic meaning, so they use it as an alignment device — but this changes the number's meaning! Octal syntax is rarely useful and can be mistakenly used, so strict mode makes octal a syntax error:

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

Seventh, strict mode in ECMAScript 6 forbids setting properties on primitive values. Without strict mode, setting properties is simply ignored (no-op), with strict mode, however, a TypeError is thrown.

(function() {
"use strict";

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

})();

Simplifying variable uses

Strict mode simplifies how variable names map to particular variable definitions in the code. Many compiler optimizations rely on the ability to say that variable X is stored in that location: this is critical to fully optimizing JavaScript code. JavaScript sometimes makes this basic mapping of name to variable definition in the code impossible to perform until runtime. Strict mode removes most cases where this happens, so the compiler can better optimize strict mode code.

First, strict mode prohibits with. The problem with with is that any name inside the block might map either to a property of the object passed to it, or to a variable in surrounding (or even global) scope, at runtime: it's impossible to know which beforehand. Strict mode makes with a syntax error, so there's no chance for a name in a with to refer to an unknown location at runtime:

"use strict";
var x = 17;
with (obj) // !!! syntax error
{
  // If this weren't strict mode, would this be var x, or
  // would it instead be obj.x?  It's impossible in general
  // to say without running the code, so the name can't be
  // optimized.
  x;
}

The simple alternative of assigning the object to a short name variable, then accessing the corresponding property on that variable, stands ready to replace with.

Second, eval of strict mode code does not introduce new variables into the surrounding scope. In normal code eval("var x;") introduces a variable x into the surrounding function or the global scope. This means that, in general, in a function containing a call to eval every name not referring to an argument or local variable must be mapped to a particular definition at runtime (because that eval might have introduced a new variable that would hide the outer variable). In strict mode eval creates variables only for the code being evaluated, so eval can't affect whether a name refers to an outer variable or some local variable:

var x = 17;
var evalX = eval("'use strict'; var x = 42; x");
console.assert(x === 17);
console.assert(evalX === 42);

Relatedly, if the function eval is invoked by an expression of the form eval(...) in strict mode code, the code will be evaluated as strict mode code. The code may explicitly invoke strict mode, but it's unnecessary to do so.

function strict1(str){
  "use strict";
  return eval(str); // str will be treated as strict mode code
}
function strict2(f, str){
  "use strict";
  return f(str); // not eval(...): str is strict if and only
                 // if it invokes strict mode
}
function nonstrict(str){
  return eval(str); // str is strict if and only 
                    // if it invokes strict mode
}

strict1("'Strict mode code!'");
strict1("'use strict'; 'Strict mode code!'");
strict2(eval, "'Non-strict code.'");
strict2(eval, "'use strict'; 'Strict mode code!'");
nonstrict("'Non-strict code.'");
nonstrict("'use strict'; 'Strict mode code!'");

Thus names in strict mode eval code behave identically to names in strict mode code not being evaluated as the result of eval.

Third, strict mode forbids deleting plain names. delete name in strict mode is a syntax error:

"use strict";

var x;
delete x; // !!! syntax error

eval("var y; delete y;"); // !!! syntax error

Making eval and arguments simpler

Strict mode makes arguments and eval less bizarrely magical. Both involve a considerable amount of magical behavior in normal code: eval to add or remove bindings and to change binding values, and arguments by its indexed properties aliasing named arguments. Strict mode makes great strides toward treating eval and arguments as keywords, although full fixes will not come until a future edition of ECMAScript.

First, the names eval and arguments can't be bound or assigned in language syntax. All these attempts to do so are syntax errors:

"use strict";
eval = 17;
arguments++;
++eval;
var obj = { set p(arguments) { } };
var eval;
try { } catch (arguments) { }
function x(eval) { }
function arguments() { }
var y = function eval() { };
var f = new Function("arguments", "'use strict'; return 17;");

Second, strict mode code doesn't alias properties of arguments objects created within it. In normal code within a function whose first argument is arg, setting arg also sets arguments[0], and vice versa (unless no arguments were provided or arguments[0] is deleted). arguments objects for strict mode functions store the original arguments when the function was invoked. arguments[i] does not track the value of the corresponding named argument, nor does a named argument track the value in the corresponding arguments[i].

function f(a){
  "use strict";
  a = 42;
  return [a, arguments[0]];
}
var pair = f(17);
console.assert(pair[0] === 42);
console.assert(pair[1] === 17);

Third, arguments.callee is no longer supported. In normal code arguments.callee refers to the enclosing function. This use case is weak: simply name the enclosing function! Moreover, arguments.callee substantially hinders optimizations like inlining functions, because it must be made possible to provide a reference to the un-inlined function if arguments.callee is accessed. arguments.callee for strict mode functions is a non-deletable property which throws when set or retrieved:

"use strict";
var f = function() { return arguments.callee; };
f(); // throws a TypeError

"Securing" JavaScript

Strict mode makes it easier to write "secure" JavaScript. Some websites now provide ways for users to write JavaScript which will be run by the website on behalf of other users. JavaScript in browsers can access the user's private information, so such JavaScript must be partially transformed before it is run, to censor access to forbidden functionality. JavaScript's flexibility makes it effectively impossible to do this without many runtime checks. Certain language functions are so pervasive that performing runtime checks has considerable performance cost. A few strict mode tweaks, plus requiring that user-submitted JavaScript be strict mode code and that it be invoked in a certain manner, substantially reduce the need for those runtime checks.

First, the value passed as this to a function in strict mode is not forced into being an object (a.k.a. "boxed"). For a normal function, this is always an object: either the provided object if called with an object-valued this; the value, boxed, if called with a Boolean, string, or number this; or the global object if called with an undefined or null this. (Use call, apply, or bind to specify a particular this.) Not only is automatic boxing a performance cost, but exposing the global object in browsers is a security hazard, because the global object provides access to functionality that "secure" JavaScript environments must restrict. Thus for a strict mode function, the specified this is not boxed into an object, and if unspecified, this will be undefined:

"use strict";
function fun() { return this; }
console.assert(fun() === undefined);
console.assert(fun.call(2) === 2);
console.assert(fun.apply(null) === null);
console.assert(fun.call(undefined) === undefined);
console.assert(fun.bind(true)() === true);

That means, among other things, that in browsers it's no longer possible to reference the window object through this inside a strict mode function.

Second, in strict mode it's no longer possible to "walk" the JavaScript stack via commonly-implemented extensions to ECMAScript. In normal code with these extensions, when a function fun is in the middle of being called, fun.caller is the function that most recently called fun, and fun.arguments is the arguments for that invocation of fun. Both extensions are problematic for "secure" JavaScript, because they allow "secured" code to access "privileged" functions and their (potentially unsecured) arguments. If fun is in strict mode, both fun.caller and fun.arguments are non-deletable properties which throw when set or retrieved:

function restricted()
{
  "use strict";
  restricted.caller;    // throws a TypeError
  restricted.arguments; // throws a TypeError
}
function privilegedInvoker()
{
  return restricted();
}
privilegedInvoker();

Third, arguments for strict mode functions no longer provide access to the corresponding function call's variables. In some old ECMAScript implementations arguments.caller was an object whose properties aliased variables in that function. This is a security hazard because it breaks the ability to hide privileged values via function abstraction; it also precludes most optimizations. For these reasons no recent browsers implement it. Yet because of its historical functionality, arguments.caller for a strict mode function is also a non-deletable property which throws when set or retrieved:

"use strict";
function fun(a, b)
{
  "use strict";
  var v = 12;
  return arguments.caller; //TypeError 가 발생.
}
fun(1, 2); // doesn't expose v (or a or b)

미래의 ECMAScript 버전을 위한 준비

새롭게 선보일 ECMAScript 버전은 새로운 구문을 소개할 것이고, ECMAScript5에서의 엄격 모드는 변환을 쉽게 하기 위해 몇 가지의 제한을 적용할 것으로 예상되고 있습니다. 만약 이 변화들이 엄격 모드에서의 제한을 기반으로 한다면, 더 바꾸기 쉬워질 것입니다.

첫번째로, 엄격 모드에서의 식별자 후보들은 예약어가 됩니다. 이 예약어들은 implements, interface, let, package, private, protected, public, staticyield입니다. 그럼, 엄격 모드에서는 이 예약어와 똑같은 이름을 사용하거나, 변수명 또는 아규먼트명으로도 사용할 수 없습니다.  

function package(protected){ // !!!
  "use strict";
  var implements; // !!!

  interface: // !!!
  while (true){
    break interface; // !!!
  }

  function private() { } // !!!
}
function fun(static) { 'use strict'; } // !!!

Mozilla의 특별 지시 두 가지 : 먼저, 코드가 JavaScript 1.7 또는 그보다 높고 (예를 들어, 크롬 코드 또는 <script type=""> 를 바로 사용할 때) 엄격 모드의 코드라면,  let 와 yield는 처음 소개되었을 때의 그 기능을 가진다. 그러나 웹에서의 엄격 모드 코드는, <script src=""><script>...</script>로 로딩되지, let/yield를 식별자로 사용할 수가 없을 것이다. 그리고 나서는, ES5 가 class, enum, export, extends, import, and super 와 같은 예약어들을 무조건 리저브함에도 불구하고, 먼저 Firefox 5 Mozilla 는 그것들을 엄격 모드에서만 리저브한다.

다음은, 엄격 모드는 스크립트나 함수의 탑 레벨이 아닌 곳에서의 함수 내용 정의를 제한합니다. (strict mode prohibits function statements not at the top level of a script or function). 브라우저에서 일반적인 코드는 함수 내용 정의가 "어디에서든" 허용됩니다. 이것은 ES5의 부분이 아닙니다!(심지어 ES3도 아니다.) 이건 다른 브라우저에서 공존할 수 없는 시멘틱의 확장입니다. 앞으로의 ECMAScript 에디션은 바라건대, 스크립트나 함수의 탑 레벨이 아닌 곳에서의 함수 내용 정의를 위해, 새로운 시멘틱을 명시할 것입니다. 엄격 모드에서 이러한 함수 정의를 금지하는 것(Prohibiting such function statements in strict mode)은 앞으로 출시될 ECMAScript의 사양을 위한 "준비"입니다.  :

"use strict";
if (true){
  function f() { } // !!! syntax error
  f();
}

for (var i = 0; i < 5; i++){
  function f2() { } // !!! syntax error
  f2();
}

function baz(){ // kosher
  function eit() { } // also kosher
}

이 규제는 엄밀히 말하면 엄격 모드가 아닌데, 저런 함수 표현식들은 기본 ECMAScript5의 확장이기 때문입니다. 그러나 이것이 ECMAScript 협회가 권장하는 방식이며, 브라우저들이 이를 지원할 것입니다. 

브라우저에서의 엄격 모드

현재 주류의 브라우저들은 엄격 모드를 지원하고 있습니다. 하지만, 아직도 현실에서 사용되는 수 많은 브라우저의 버전들은 엄격 모드를 부분적으로만 지원하거나(Browser versions used in the wild that only have partial support for strict mode), 아예 지원을 하지 않고 있기 때문에, 맹목적으로 여기에 의지할 수는 없습니다. (예를 들면, Internet Explorer 10 버전 이하!) 엄격 모드는 시멘틱을 바꿉니다. 이 변화들에 의지하는 것은 실수와 엄격 모드를 지원하지 않는 브라우저의 에러를 야기할 것입니다. 엄격 모드를 사용하는 데에 주의하는 것을 익히세요, 그리고 피쳐 테스트로 엄격 모드를 사용하기에 적절한 부분인지 확인하고 보완하세요. 마지막으로, 엄격 모드를 지원하는 브라우저와 그렇지 않은 브라우저에서 작성한 코드의 테스트를 확실히 하도록 하세요. 

스펙

Specification Status Comment
ECMAScript 5.1 (ECMA-262)
The definition of 'Strict Mode Code' in that specification.
Standard 초기 정의. 참조 : Strict mode restriction and exceptions
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Strict Mode Code' in that specification.
Standard Strict mode restriction and exceptions
ECMAScript 2017 Draft (ECMA-262)
The definition of 'Strict Mode Code' in that specification.
Draft Strict mode restriction and exceptions

참조

문서 태그 및 공헌자

 이 페이지의 공헌자: imskojs, magnoliaa
 최종 변경: imskojs,