14일 10월 2019

Eval: 문자열 코드 실행하기

내장 함수 eval을 사용하면 문자열 형태의 코드를 실행할 수 있습니다.

문법은 다음과 같습니다.

let result = eval(code);

예시:

let code = 'alert("Hello")';
eval(code); // Hello

길이가 긴 문자열이 코드가 될 수 있는데, 여기엔 줄 바꿈, 함수 선언, 변수 등이 포함될 수도 있습니다.

마지막 구문의 결과가 eval의 결과가 됩니다.

예시:

let value = eval('1+1');
alert(value); // 2
let value = eval('let i = 0; ++i');
alert(value); // 1

eval로 둘러싼 코드는 현재 렉시컬 환경에서 실행되므로 외부 변수에 접근할 수 있습니다.

let a = 1;

function f() {
  let a = 2;

  eval('alert(a)'); // 2
}

f();

외부 변수를 변경하는 것도 가능하죠.

let x = 5;
eval("x = 10");
alert(x); // 10, 변경된 값

엄격 모드에서 eval은 자체 렉시컬 환경을 갖고 있습니다. 따라서 eval 내부에 선언된 함수와 변수는 외부에서 읽을 수 없습니다.

// 참고: 실행 가능한 모든 예시에 'use strict'가 적용되어있습니다.

eval("let x = 5; function f() {}");

alert(typeof x); // undefined (없는 변수)
// 함수 f도 읽을 수 없음

use strict가 적용되어있지 않은 경우엔 eval은 자체 렉시컬 환경을 갖지 않기 때문에 외부에 있는 xf를 읽을 수 있습니다.

‘eval’ 사용하기

eval은 모던 프로그래밍에서 잘 사용되지 않습니다. "eval is evil(악마)"이라고까지 불리죠.

이유는 간단합니다. 과거엔 자바스크립트에서 쓸 수 있는 기능이 많지 않았기 때문에 eval을 사용해야만 처리할 수 있는 것들이 많았습니다. 하지만 그 이후로 10여 년이 흐르면서 자바스크립트는 강력한 언어로 변모하였죠.

지금은 eval을 사용할 이유가 거의 없습니다. 누군가가 여전히 eval을 사용하고 있다면, 모던한 언어 문법이나 모듈을 사용해 코드를 바꾸는 걸 권유해 보시기 바랍니다.

eval을 사용할 땐 외부 변수에 접근 시 부작용이 발생한다는 점에 유의하셔야 합니다.

애플리케이션이 출시 되기 전에 자바스크립트 파일을 압축해주는 도구인 코드 압축기(minifier)는 스크립트 크기를 줄이기 위해 지역 변수명을 ab같이 짧게 변경합니다. 대개는 이 과정에서 부작용이 발생하지 않지만, eval을 사용하면 eval로 감싼 코드에서 지역 변수에 접근할 수 있으므로 안전하지 않습니다. 이런 위험을 방지하기 위해 압축기는 eval 내부 코드에서 접근할 가능성이 있는 모든 변수의 이름을 변경하지 않습니다. 이는 코드 압축률에 부정적인 영향을 미칩니다.

eval 내부에서 외부 지역 변수를 사용하는 것은 코드 유지 보수를 더 어렵게 만들기 때문에 좋지 않은 프로그래밍 관습으로 취급되기도 합니다.

위와 같은 문제는 아래에서 소개해 드릴 방법 두 개를 사용해 예방할 수 있습니다.

eval로 감싼 코드에서 외부 변수를 사용하지 않는다면 eval 대신 window.eval(...)을 호출하세요.

이렇게 하면 eval 내의 코드가 전역 스코프에서 실행됩니다.

let x = 1;
{
  let x = 5;
  window.eval('alert(x)'); // 1 (전역 변수)
}

eval로 감싼 코드에서 지역 변수를 사용한다면, eval이 아닌 new Function에 문자열로 된 코드를 전달하세요.

let f = new Function('a', 'alert(a)');

f(5); // 5

new Function 문법(자세한 내용은 'new Function' 문법 챕터에서 살펴봄)은 인수로 받은 문자열을 기반으로 전역 스코프에 새로운 함수를 만들어줍니다. 따라서 지역 변수에 접근할 수 없죠. 하지만 위 예시에서처럼 코드 내부에서 지역 변수에 접근하지 말고 인수를 통해 값을 받는 게 훨씬 더 명확하다는 것을 알고 계시기 바랍니다.

요약

eval(code)을 호출하면 문자열 형태의 code가 실행되는데 이때 마지막 구문의 결과가 반환됩니다.

  • 모던 자바스크립트엔 eval을 대체할 수 있는 문법이 많기 때문에, 모던 자바스크립트를 사용하는 코드에선 eval을 잘 사용하지 않습니다.
  • eval을 이용해 만든 코드는 외부 지역 변수에 접근할 수 있는데, 이는 좋지 않은 방법입니다.
  • 전역 스코프에서 eval을 사용하지 말고, window.eval(code)을 이용하세요.
  • 외부 스코프에 있는 데이터가 필요하다면 new Function의 인수에 코드를 전달해 사용하시면 됩니다.

과제

중요도: 4

산술 표현식을 입력받는 프롬프트 대화상자를 표시하고 결과를 반환하는 계산기를 만들어봅시다.

입력한 표현식이 정확한 지 확인할 필요는 없고, 결과를 평가하고 반환하기만 하면 됩니다.

데모 실행하기

산술 표현식을 계산하기 위해 eval을 사용해봅시다.

let expr = prompt("산술 표현식을 입력하시겠습니까?", '2*3+2');

alert( eval(expr) );

사용자는 텍스트 또는 코드를 입력할 수 있습니다.

문자열을 산술 표현식만 입력하도록 제한하여 안전하게 eval로 실행하기 위해, 정규 표현식을 사용하여 expr을 검사하면 숫자와 연산자만 포함하게 됩니다.

튜토리얼 지도

댓글

댓글을 달기 전에 마우스를 올렸을 때 나타나는 글을 먼저 읽어주세요.
  • 추가 코멘트, 질문 및 답변을 자유롭게 남겨주세요. 개선해야 할 것이 있다면 댓글 대신 이슈를 만들어주세요.
  • 잘 이해되지 않는 부분은 구체적으로 언급해주세요.
  • 댓글에 한 줄짜리 코드를 삽입하고 싶다면 <code> 태그를, 여러 줄로 구성된 코드를 삽입하고 싶다면 <pre> 태그를 이용하세요. 10줄 이상의 코드는 plnkr, JSBin, codepen 등의 샌드박스를 사용하세요.