[모던 자바스크립트 튜토리얼] 6.7 new Function 문

개발견 배도르만·2023년 5월 4일
0
post-thumbnail

new Function 문법

함수 만드는 방법 세 가지

  1. 함수 표현식
  2. 함수 선언문
  3. new Function 문법

new Function 문법은 잘 사용되진 않지만, 이 방법 외에는 대안이 없을 때 사용한다.

let func = new Function ([arg1, arg2, ...argN], functionBody);

새로 만들어지는 함수는
인수 arg1...argN
함수 본문 functionBody
로 구성된다.

인수 두 개가 있는 함수를 직접 만들어 보면서 new Function 문법에 대해 이해해보자.

let sum = new Function('a', 'b', 'return a + b');

alert( sum(1, 2) ); // 3
인수가 없고 함수 본문만 있는 함수를 만들어보겠습니다.

let sayHi = new Function('alert("Hello")');

sayHi(); // Hello

기존에 사용하던 방법과 new Function을 사용해 함수를 만드는 방법의 가장 큰 차이는 런타임에 받은 문자열을 사용해 함수를 만들 수 있다는 점이다.

let str = ... 서버에서 동적으로 전달받은 문자열(코드 형태) ...

let func = new Function(str);
func();

서버에서 코드를 받거나 템플릿을 사용해 함수를 동적으로 컴파일해야 하는 경우, 복잡한 웹 애플리케이션을 구현할 때와 같이 아주 특별한 경우에 new Function을 사용할 수 있다.

클로저

함수는 특별한 프로퍼티 [[Environment]]에 저장된 정보를 이용해 자기 자신이 태어난 곳(함수가 만들어진 렉시컬 환경)을 기억(참조)한다.
6.3 유효범위와 클로저 참고

그런데 new Function을 이용해 함수를 만들면 함수의 [[Environment]] 프로퍼티가 현재 렉시컬 환경이 아닌 전역 렉시컬 환경을 참조하게 된다.

따라서 new Function을 이용해 만든 함수는 외부 변수에 접근할 수 없고, 오직 전역 변수에만 접근할 수 있습니다.

function getFunc() {
  let value = "test";

  let func = new Function('alert(value)');

  return func;
}


getFunc()(); // ReferenceError: value is not defined

일반적인 방법을 사용해 함수를 정의한 예시와 비교

function getFunc() {
  let value = "test";

  let func = function() { alert(value); };

  return func;
}

getFunc()(); // getFunc의 렉시컬 환경에 있는 값 "test"가 출력됩니다.

외부 변수에 접근하지 못하는 이유

스크립트가 프로덕션 서버에 반영되기 전, 압축기(minifier)*지역 변수 이름을 짧게 바꾸면서 문제가 발생한다.

new Function 문법으로 만든 함수 내부에서 외부 변수에 접근하려고 하면 userName은 이미 이름이 변경되었기 때문에 찾을 수 없게 되는 것이다.

  • *압축기 : 스크립트에서 주석이나 여분의 공백 등을 없애 코드 크기를 줄여주는 특수한 프로그램

예를 들어, 함수 내부에 let userName라는 변수가 있으면 이 지역변수는 압축기에 의해 let a 등(짧은 이름)으로 대체되는데, 이때 userName 모두가 a로 교체된다.

userName은 지역변수이고, 함수 외부에선 함수 내부에 있는 변수에 접근할 수 없기 때문에 이렇게 해도 전혀 문제가 없다.
압축기는 단순히 변수를 찾아서 바꾸지 않고 코드 구조를 분석해 기존에 작성한 코드의 기능을 망가뜨리지 않으면서 영리하게 제 역할을 수행한다.

이러한 동작 방식 때문에 압축기가 동작한 이후엔, new Function으로 만든 함수 내부에서 외부 렉시컬 환경에 접근하려고 할 때 문제가 발생할 수 있다.

결론

함수 내부에서 외부 변수에 접근하는 것은 아키텍처 관점에서도 좋지 않고 에러에 취약하므로, new Function으로 만든 함수에 무언갈 넘겨주고 싶다면 인자를 사용하자.

✍️ 정리

  • 문법:
let func = new Function ([arg1, arg2, ...argN], functionBody);
  • 인수를 한꺼번에 모아(쉼표로 구분) 전달할 수도 있다(아래 세 선언 방식은 동일하게 동작).
new Function('a', 'b', 'return a + b'); // 기본 문법
new Function('a,b', 'return a + b'); // 쉼표로 구분
new Function('a , b', 'return a + b'); // 쉼표와 공백으로 구분
  • new Function을 이용해 만든 함수의 [[Environment]]는 외부 렉시컬 환경이 아닌 전역 렉시컬 환경을 참조하므로 외부 변수를 사용할 수 없다.
    • 단점 같아 보이는 특징이긴 하지만 에러를 예방해 준다는 관점에선 장점이 되기도 한다.
    • 구조상으론 매개변수를 사용해 값을 받는 게 더 낫다. 압축기에 의한 에러도 방지할 수 있다.
profile
네 발 개발 개

0개의 댓글