JavaScript
JavaScript의 제한된 버전을 선택하여 기본값인 sloppy mode를 해제하는 방법으로, 일반적인 코드와 다른 semantics를 지니고 있다. 하지만 sloppy mode와 strict mode의 코드는 공존할 수 있어, 차후 strict mode를 이용하여 스크립트의 모드를 변경할 수도 있다.
그래서 strict mode란 무엇일까?
- 기존에 문제를 발생시키지 않고 조용히 무시되던 에러들을 throwing한다.
- JavaScript 엔진의 최적화 작업을 어렵게 만드는 실수들을 바로잡는다. 이는 동일한 내용이지만 sloppy mode 코드일 때보다 더 빨리 작동하도록 돕는다.
- 이후의 ECMAScript 업데이트로 인한 자동적인 변경을 제한한다.
- 모듈은 기본적으로 strict mode이다.
이를 적용하는 조건은 다음과 같다.
1 | // 스크립트 전체 |
전체 스크립트 또는 부분 함수에 적용 가능하다.
{} 로 묶여진 블럭문에는 적용되지 않는다. 따라서, context와 같은 곳에 적용을 시도하면 동작하지 않는다.
eval, Function 코드, 이벤트 핸들러 속성, setTimeout() 등의 함수에 전달된 문자열은 전체 스크립트로, 적용 가능하다.
변경 사항
이러한 strict mode는 구문과 런타임 동작 등을 모두 변경시킨다. 예를 들어,
- 변환 실수를 오류로 해석하거나 (문법 오류/ 런타임 에러 발생),
- 특정 이름의 특정 용도에 대한 특정 변수를 계산하는 방법을 단순화하며,
eval
과arguments
를 단순화하고,- “안전한 “자바 스크립트를 작성하도록 돕고,
- 미래 ECMAScript의 진화에 대비합니다.
위와 같은 변경으로 인해, 기존에는 인정되던 실수를 에러로 인식하여 발생시킨다.
글로벌 변수를 생성하는 것을 금한다.
1
2
3"use strict";
// 전역 변수 mistypedVariable 이 존재한다고 가정
mistypedVaraible = 17; // ReferenceError 를 발생시킴일반 코드에서 조용히 넘어가는 모든 실패 (쓸 수 없는 전역 또는 프로퍼티에 할당, getter-only 프로퍼티에 할당, 확장 불가 객체에 새 프로퍼티 할당) 에 대해 예외를 발생시킨다.
NaN
은 쓸 수 없는 전역 변수 (NaN
에 할당하는 일반적인 코드는 아무 것도 하지 않는다. ) 로, 예외를 발생시킨다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19;
// 쓸 수 없는 프로퍼티에 할당
var undefined = 5; // TypeError 발생
var Infinity = 5; // TypeError 발생
// 쓸 수 없는 프로퍼티에 할당
var obj1 = {};
Object.defineProperty(obj1, "x", { value: 42, writable: false });
obj1.x = 9; // TypeError 발생
// getter-only 프로퍼티에 할당
var obj2 = { get x() { return 17; } };
obj2.x = 5; // TypeError 발생
// 확장 불가 객체에 새 프로퍼티 할당
var fixed = {};
Object.preventExtensions(fixed);
fixed.newProp = "ohai"; // TypeError 발생삭제할 수 없는 프로퍼티를 삭제하려 할 때; 시도가 어떤 효과도 없을 때, 예외를 발생시킨다.
1
2;
delete Object.prototype; // TypeError 발생일반 코드에서는 마지막으로 중복된 인수가 이전에 지정된 인수를 숨기지만, 유니크한 함수 파라미터 이름을 요구한다.
1
2
3
4function sum(a, a, c){ // !!! 구문 에러
;
return a + b + c; // 코드가 실행되면 잘못된 것임
}
장점
변수 사용 단순화
- 코드상의 변수 이름을 특정 변수 정의로 매핑하는 방법을 단순화한다.
- 자바스크립트는 때때로 이름을 코드상의 변수 정의로 기본 매핑하는 것을 런타임때까지 실행이 불가하게 하는데, 이것이 발생하는 대부분의 경우를 제거하여 컴파일러가 strict mode 코드를 더 잘 최적화 할 수 있게 한다.
with
를 사용하지 못하게 한다.셋째로, 엄격모드는 일반 이름을 제거하는 것을 금지합니다. 엄격 모드에서
delete name
은 구문 에러입니다.1
2
3
4
5
6;
var x;
delete x; // !!! 구문 에러
eval("var y; delete y;"); // !!! syntax error
eval 과 arguments 를 더 간단하게 하기
바인딩을 추가하거나 삭제하고 바인딩 값을 변경하기 위한
eval
명명된 인수를 가리키는, indexed 프로퍼티
arguments
JavaScript “보안”
브라우저에서 자바스크립트는 사용자의 개인정보에 접근할 수 있기 때문에, 자바스크립트는 금지된 기능에 접근을 막기 위해 실행 전, 반드시 부분적으로 변경되어야 한다. 하지만 자바스크립트의 유연성으로 인해 런타임 체크없이 이것을 수행하는 것은 사실상 불가능하다. strict mode를 이용하면 특정 방식으로 호출되므로 런타임 검사의 필요성이 크게 줄어든다.
this
로 함수에 전달된 값은 강제로 객체가 되지 않는다 (a.k.a. “boxed”). 즉, 브라우저에서 엄격모드의 함수내 에서는 더 이상window
객체를this
를 통해 참조할 수 없다.- 정의된
this
는 boxed 객체가 되지 않으며, - 정의되지 않은 경우
this
는undefined
가 된다.
- 정의된
미래의 ECMAScript 버전을 위한 준비
- 새롭게 선보일 ECMAScript 버전은 새로운 구문을 소개할 것이고, ECMAScript5에서의 엄격 모드는 변환을 쉽게 하기 위해 몇 가지의 제한을 적용한다.
React
아래와 같은 코드를 index.js
에서 많이 보았을 것이다.
1 | import React from 'react'; |
React에서 strict mode는 <React.StrictMode></React.StrictMode>
을 이용해 적용한다.
- StrictMode는 잠재적인 에러를 잡는 툴이다.
- Fragment와 같이, StrictMode는 가시적인 UI를 렌더링하지 않지만, 안에 정의되는 후손 (자식 노드) 들에 추가적인 검사를 시행하고 경고를 띄운다.
- strict mode 체크는 development mode에서만 시행되고, production 빌딩에 영향을 주지 않는다.
1 | import React from 'react'; |
- StrictMode는
Header
나Footer
컴포넌트에 영향을 주지 않는다. - 하지만,
ComponentOne
과ComponentTwo
및 그 후손들은 영향을 받는다.
React에서 strict mode는 어떻게 작동할까?
- 안전하지 않은 생명주기를 사용하는 컴포넌트 발견
- 레거시 문자열 ref 사용에 대한 경고
- 권장되지 않는 findDOMNode 사용에 대한 경고
- 예상치 못한 부작용 검사
- 레거시 context API 검사
이를 좀 더 자세히 알아보자.
특징
안전하지 않은 생명주기를 사용하는 컴포넌트 발견
Strict 모드가 활성화되면, React는 안전하지 않은 생명주기 메서드를 사용하는 모든 클래스 컴포넌트 목록을 정리해 다음과 같이 컴포넌트에 대한 정보가 담긴 경고 로그를 출력한다.
레거시 문자열 ref 사용에 대한 경고
이전의 React에서 레거시 문자열 ref API와 콜백 API라는, ref를 관리하는 두 가지 방법을 제공하였었다. 이제는 객체 ref가 문자열 ref를 교체하는 용도로 널리 더해졌기 때문에, Strict 모드는 문자열 ref의 사용에 대해 경고한다.
권장되지 않는 findDOMNode 사용에 대한 경고
이전의 React에서 주어진 클래스 인스턴스를 바탕으로 트리를 탐색해 DOM 노드를 찾을 수 있는 findDOMNode
를 지원하였었다. 이제는 DOM 노드에 바로 ref를 지정할 수 있기 때문에 보통 필요로 하지 않는다.
예상치 못한 부작용 검사
개념적으로 React는 두 단계로 동작한다.
렌더링 단계
는 특정 환경 (DOM과 같은) 에 어떤 변화가 필요한 지 결정하는 단계로, 이 과정에서 React는render
를 호출하여 이전 렌더와 결과값을 비교한다.커밋 단계
는 React가 변경 사항을 반영하는 단계로 (React DOM의 경우 React가 DOM 노드를 추가, 변경 및 제거하는 단계), 이 단계에서 React는componentDidMount
나componentDidUpdate
와 같은 생명주기 메서드를 호출한다.
커밋 단계는 일반적으로 매우 빠르지만, 렌더링 단계는 느릴 수 있어 문제가 발생할 수 있다.
)
특히 위의 메서드들은 여러 번 호출될 수 있기 때문에, 부작용을 포함하지 않는 것이 중요하다. Strict 모드가 자동으로 부작용을 찾아주는 것은 불가능하지만, 조금 더 예측할 수 있게끔 만들어서 문제가 되는 부분을 발견할 수 있게 도와준다.
이를 위해 다음과 같은 함수를 의도적으로 이중으로 호출하여 찾을 수 있다.
- 클래스 컴포넌트의
constructor
,render
그리고shouldComponentUpdate
메서드 - 클래스 컴포넌트의
getDerivedStateFromProps
static 메서드 - 함수 컴포넌트 바디
- State updater 함수 (
setState
의 첫 번째 인자) useState
,useMemo
그리고useReducer
에 전달되는 함수
레거시 context API 검사
레거시 context API는 오류가 발생하기 쉬워 이후 릴리즈에서 삭제될 예정이다.
Reference
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode