번역 작업 진행중입니다.

eval() 은 문자로써 표현된 자바스크립트 코드를 실행하는 함수입니다.

구문

eval(string)

매개변수

string
자바스크립트 표현식, 명령문, 또는 연속되는 다수의 명령문을 나타내는 문자열. 표현식은 이미 존재하는 객체의 변수나 속성을 포함할 수 있습니다.

반환값

주어진 코드를 평가하여 얻은 값. 값이 없다면 undefined를 반환합니다.

설명

eval()은 전역 객체의 함수 속성입니다.

eval()의 인자는 문자열입니다. 인자가 표현식을 나타낸다면 eval() 은 표현식을 평가합니다. 인자가 하나 이상의 자바스크립트 명령문을 나타낸다면 모두 실행합니다. 연산식을 계산하기 위해 eval() 을 호출하지 마세요. 자바스크립트는 연산식을 자동으로 계산합니다.

문자열로 연산식을 구성한다면 나중에 eval()로 계산할 수 있습니다. x 라는 변수가 있다고 가정하면 x가 포함된 연산식을 문자열로, 예를 들어 "3 * x + 2"로 나타내고 나중에 eval()을 호출해서 계산을 연기할 수 있습니다.

eval()의 인자가 문자열이 아니면 eval()은 인자를 바꾸지 않고 반환합니다. 다음 예시에서, String 생성자가 명시된 경우 문자열을 계산하는 대신 String 객체를 반환합니다.

eval(new String("2 + 2")); // "2 + 2"를 포함한 String 객체를 반환
eval("2 + 2");             // 4를 반환

toString() 을 사용하는 일반적인 방식으로 제약을 피할 수 있습니다.

var expression = new String("2 + 2");   
eval(expression.toString());

eval을 직접 호출하지 않고 참조를 통해 간접적으로 사용한다면 ECMAScript 5부터는 지역 스코프 대신 전역 스코프 에서 동작합니다. 예컨대 이는, 함수 선언은 전역 함수를 생성한다는 의미이고, 수행될 코드는 호출된 지역 스코프에 접근하지 못함을 의미합니다.

function test() {
  var x = 2, y = 4;
  console.log(eval('x + y'));  // Direct call, uses local scope, result is 6
  var geval = eval; // equivalent to calling eval in the global scope
  console.log(geval('x + y')); // Indirect call, uses global scope, throws ReferenceError because `x` is undefined
  (0, eval)('x + y'); // another example of Indirect call
}

불필요하게 eval 을 사용하지 마라!

eval() 은 caller 의 특권으로 통과한 코드를 수행하는 위험한 함수이다. 당신이 악의적인 영향을 받을 수 있는 문자열을 eval() 로 실행한다면, 당신의 웹페이지 / 확장프로그램의 허가를 가지는 사용자의 기계에서 악의적인 코드를 수행하게 될 것이다. 더 중요한건,  제 3의 코드가 eval() 이 적용된 스코프를 볼 수 있으며, 이것이 비슷한 Function 은 민감하지 않다는 면에서 공격 가능성을 야기할 수 있다.

또한 eval() 은 요즘 JS 엔진에 의해 최적화된 많은 다른 구조들에 비해, JS interpreter 를 적용해야 하기 때문에, 일반적으로 대안들보다 느리다.

eval() 의 일반적인 사용법을 위한 안전한 (그리고 빠른!) 대안이 있다.

멤버 프로퍼티들의 접근

당신은 프로퍼티들 내에서 프로퍼티 명을 변환하기 위해 eval() 을 사용해선 안된다. 코드가 실행될 때까지 접근될 객체의 프로퍼티가 알려져 있지 않은 다음의 예제를 고려해라. 이것은 eval 과 함께 사용될 수 있다:

var obj = { a: 20, b: 30 };
var propname = getPropName();  // "a" 또는 "b" 를 반환

eval( "var result = obj." + propname );

그러나, eval() 은 여기에 불필요하다. 사실, 여기서 그것을 사용하는 것은 말릴 일이다. 대신, 훨씬 빠르고 안전한 property accessors 를 사용해라:

var obj = { a: 20, b: 30 };
var propname = getPropName();  // "a" 또는 "b" 를 반환
var result = obj[ propname ];  //  obj[ "a" ] 는 obj.a 와 동일함

이 메서드를 사용하여 내부의 프로퍼티에도 접근할 수 있다. 여기서 eval()은 다음과 같이 사용할 수 있다:

var obj = {a: {b: {c: 0}}};
var propPath = getPropPath();  // "a.b.c"를 반환한다고 가정

eval( 'var result = obj.' + propPath );

여기서 eval()의 사용을 피하려면 프로퍼티 경로를 나누어(split) 각각의 프로퍼티를 순회할 수도 있다:

function getDescendantProp(obj, desc) {
  var arr = desc.split('.');
  while (arr.length) {
    obj = obj[arr.shift()];
  }
  return obj;
}

var obj = {a: {b: {c: 0}}};
var propPath = getPropPath();  // "a.b.c"를 반환한다고 가정
var result = getDescendantProp(obj, propPath);

프로퍼티에 값을 세팅하는 것은 비슷한 방법으로 구현할 수 있다:

function setDescendantProp(obj, desc, value) {
  var arr = desc.split('.');
  while (arr.length > 1) {
    obj = obj[arr.shift()];
  }
  return obj[arr[0]] = value;
}

var obj = {a: {b: {c: 0}}};
var propPath = getPropPath();  // "a.b.c"를 반환한다고 가정
var result = setDescendantProp(obj, propPath, 1);  // test.a.b.c의 값은 1로 지정됨

단편적인 코드 수행 대신 함수를 사용

JavaScript 는 함수를 다른 API의 파라미터로 전달할 수 있고, 다른 객체의 프로퍼티나 변수에 저장할 수 있는 등의 1급 함수를 가진다. 많은 DOM API들이 이 점을 염두하여 설계되며, 그래서 당신은 쓸 수 있다(써야 한다). 

// setTimeout(" ... ", 1000) 대신에 사용:
setTimeout(function() { ... }, 1000); 

// elt.setAttribute("onclick", "...") 대신에 사용:
elt.addEventListener("click", function() { ... } , false); 

또한 클로저는 연결된 문자열 없이 매개 변수화 된 함수들을 생성하는데 유용하다. 

JSON 파싱 (문자열을 JavaScript 객체로 변환)

만약 당신이 eval() 을 호출하려는 문자열에 코드가 아니라 데이터가 포함되어 있다면, (예를 들어, 배열: "[1, 2, 3]"), 당신은 JSON으로 변환하는 것을 고려해야 한다. 이것은 문자열이 데이터를 대신하기 위해 JavaScript 문법의 일부를 사용하는 것을 허용한다. 또한 Downloading JSON and JavaScript in extensions 를 보자.

JSON 문법이 JavaScript 문법에 비해 제약이 있기 때문에, 많은 유효한 JavaScript 리터럴은 JSON 으로 변환하지 않을 것이다. 예를 들어, 콤마의 연속은 JSON 으로 허용되지 않고, 객체 리터럴에서 프로퍼티 명(키)은 반드시  따옴표로 감싸야 한다. 추후 JSON 으로 변환될 문자열을 만들어 내기 위해 JSON serializer(직렬변환기) 를 사용하자. 

코드 대신에 데이터 전달

예를 들어, 웹 페이지의 컨텐츠를 스크랩 하기 위해 설계된 확장 프로그램은 JavaScript 코드 대신 XPath 에 스크랩 규칙을 가질 수 있을 것이다.

제한된 특권으로 코드 실행

당신이 코드를 실행시켜야 한다면, 축소한 특권으로 실행하도록 고려해라. 이 조언은 주로 확장 프로그램이나 XUL 어플리케이션에 적용되며, 이에 Components.utils.evalInSandbox 를 사용할 수 있다. 

예제

eval 사용하기

다음의 코드에서, eval() 를 포함하는 문들은 모두 42를 반환한다. 첫번째는 "x + y + 1" 문자열을 수행한다; 두번째는 "42" 라는 문자열을 수행한다.

var x = 2;
var y = 39;
var z = "42";
eval("x + y + 1"); // 42 를 반환
eval(z);           // 42 를 반환

JavaScript 문 문자열을 수행하기 위해 eval  사용하기

다음의 예제에서 str 문자열을 수행하기 위해 eval() 을 사용한다. 이 문자열은 x가 5이면 console 에 로그를 남긴 다음 z 에 42 를 할당하고, 그 밖의 경우에는 z 에 0 을 할당하는 JavaScript 문들로 구성되어 있다. 두 번째 문이 실행되면, eval() 은 이 문들이 수행되도록 할 것이고, 문들의 집합을 수행할 것이고, z 에 할당된 값을 반환할 것이다.

var x = 5;
var str = "if (x == 5) {console.log('z is 42'); z = 42;} else z = 0; ";

console.log("z is ", eval(str));

다중 값을 정의한다면 마지막의 값이 반환된다.

var x = 5;
var str = "if (x == 5) {console.log('z is 42'); z = 42; x = 420; } else z = 0;"; 

console.log('x is ', eval(str)); // z는 42  x는 420

 

마지막 표현식이 수행된다

eval() 은 마지막 표현식의 수행된 값을 반환한다.

var str = "if ( a ) { 1+1; } else { 1+2; }";
var a = true;
var b = eval(str);  // 2를 반환
 
console.log("b is : " + b);

a = false;
b = eval(str);  // 3을 반환

console.log("b is : " + b);

함수 정의 문자열로써의 eval 은 "("와 ")"가 각각 앞과 뒤에 필요하다 

var fctStr1 = "function a() {}"
var fctStr2 = "(function a() {})"
var fct1 = eval(fctStr1)  // undefined 을 반환
var fct2 = eval(fctStr2)  // 함수를 반환

명세서

명세 상태 내용
ECMAScript 1st Edition (ECMA-262) Standard 최초 정의.
ECMAScript 5.1 (ECMA-262)
The definition of 'eval' in that specification.
Standard  
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'eval' in that specification.
Standard  
ECMAScript Latest Draft (ECMA-262)
The definition of 'eval' in that specification.
Draft  

브라우저 호환성

FeatureChromeEdgeFirefoxInternet ExplorerOperaSafari
Basic support Yes Yes1 Yes Yes Yes
FeatureAndroid webviewChrome for AndroidEdge mobileFirefox for AndroidOpera AndroidiOS SafariSamsung Internet
Basic support Yes Yes Yes4 Yes Yes Yes

Firefox 명세 노트

  • 역사적으로 eval() 은 수행될 context 를 지정하는 선택적인 두 번째 인자가 있었다. 이 인자는 비 표준이었고, Gecko 1.9.1 (Firefox 3.5) 에 SpiderMonkey 로부터 제거되었다. bug 442333 를 참고.

참고

문서 태그 및 공헌자

태그: 
이 페이지의 공헌자: urty5656, LOG91, goeo1066, desty, nicesh
최종 변경: urty5656,