surf core js : new Function()

Dino_·2021년 9월 5일
0

surf javascript

목록 보기
26/28
post-thumbnail

🌳 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을 사용해 함수를 만드는 방법의 가장 큰 차이는 런타임에 받은 문자열을 사용해 함수를 만들 수 있다는 점이다.

함수 표현식과 함수 선언문은 개발자가 직접 스크립트를 작성해야만 함수를 만들 수 있었지만, new Function이라는 문법을 사용하면 어떤 문자열도 함수로 바꿀 수 있다.

서버에서 전달받은 문자열을 이용해 새로운 함수를 만들고 이를 실행하는 것도 가능하다.

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

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

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

🍃 클로저

함수는 특별한 프로퍼티 [[Environment]]에 저장된 정보를 이용해 자기 자신이 태어난 곳을 기억한다.

[[Environment]]는 함수가 만들어진 렉시컬 환경을 참조한다.

그런데 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"가 출력됩니다.

문자열을 사용해서 함수를 만들어야 한다고 가정해본다면, 스크립트를 작성하는 시점엔 어떻게 함수를 짤지 알 수 없어서 기존의 함수 선언 방법은 사용하지 못하는데, 스크립트 실행 시점 즈음엔 함수를 어떻게 짜야 할 지 아이디어가 떠오를 수 있을 것이다.

이때, 서버를 비롯한 외부 출처를 통해 코드를 받아올 수 있겠다.

그런데 이렇게 만들어진 새 함수는 기존 스크립트와 문제없이 상호작용할 수 있어야 한다.

new Function으로 만든 새로운 함수 내부에서 외부 변수에 접근하려 할 때, 기존 함수 선언 방식으로 작성한 함수와 동일한 동작이 보장되어야 한다.

그런데 스크립트가 프로덕션 서버에 반영되기 전, 압축기(minifier) 에 의해 압축될 때 문제가 발생한다. 압축기는 스크립트에서 주석이나 여분의 공백 등을 없애 코드 크기를 줄여주는 특수한 프로그램인데 압축기가 지역 변수 이름을 짧게 바꾸면서 문제가 발생한다.

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

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

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

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

이런 실수로부터 예방하기 위해 new Function에는 특별한 기능이 있다. new Function으로 만든 함수에 무언갈 넘겨주고 싶다면 인수를 사용하자.

new Function('a', 'b', 'return a + b'); // 기본 문법
new Function('a,b', 'return a + b'); // 쉼표로 구분
new Function('a , b', 'return a + b'); // 쉼표와 공백으로 구분

🌳 Reference

profile
호기심 많은 청년

0개의 댓글