eval() 사용과 문제점 : #eval() is evil
eval() is evil
코드에서 eval()
을 발견하면 'eval() 은 사악하다(eval() is evil)'라는 주문을 기억하라!
이 함수는 임의의 문자열을 받아 자바스크립트 코드로 실행합니다.
만약 문제의 코드를 사전에 알 수 있다면(즉 런타임에 결정되는 게 아니라면) eval()을 쓸 필요가 없습니다.
코드가 런타임에 동적으로 생성된다면 대개 eval() 없이 목표를 달성할 수 있는 더 나은 방법이 존재합니다.
eval() 피하기
예컨대 동적인 프로퍼티에 접근하려고 할때는 대괄호 표기법이 더 간단하고 좋은 방법이 될 것입니다.
// 안티 패턴
var property = 'name';
console.log(eval('obj.' + property));
// 권장 패턴
var property = 'name';
console.log(obj[property]);
eval()
사용은 보안 문제와도 관련됩니다. 누군가 함부로 손댄(예를 들어 네트워크에서 가져온) 코드를 실행시키게 될 수도 있기 때문입니다.
Ajax 요청으로 받아온 JSON 응답을 다룰 때 이런 안티 패턴을 흔히 볼 수 있습니다.
보안과 유효성을 보장하기 위해서는 브라우저의 내장 메서드를 사용하여 JSON 응답을 파상하는 것이 좋습니다.
JSON.parse()
를 내장 지원하지 않느 브라우저에서는 JSON.org 의 라이브러리를 사용할 수 있습니다.
또 하나, setInterval()
과 setTimeout()
그리고 Function()
생성자에 문자열을 넘기는 것도 eval() 을
사용하는 것과 상당히 비슷하기 때문에, 역시 사용을 자제해야 합니다.
자바스크립트가 전달받은 문자열을 프로그래밍 코드로 평가하여 실행하는 것은 마찬가지입니다.
// 안티 패턴
setTimeout('myFunc()', 3000);
setTimeout('myFunc(1, 2, 3)', 1000);
// 권장 패턴
setTimeout(myFunc, 3000);
setTimeout(function () {
myFunc(1, 2, 3);
}, 1000)
new Function()
생성자를 사용하는 것도 eval() 과 비슷하기 때문에 신중하게 접근해야 합니다.
강력한 도구가 될 수도 있지만 대부분 제대로 사용되지 않습니다.
반드시 eval()
을 사용해야만 한다면 그 대신에 new Function()
의 사용을 고려해볼 수 있습니다.
new Function()
안에서 평가되는 코드는 지역 함수의 유효범위 안에서 실행되기 때문에 코드 내에서 var 로 선언된 변수들이 자동으로 전역 변수가 되지 않는
약간의 장점이 있습니다.
자동으로 전역 변수가 되지 못하도록 막기 위해 eval()
호출을 즉시실행 함수로 감싸는 방법도 있습니다.
다음의 예제를 살펴보도록 합니다. 여기서 전역 변수로 남아 네임스페이스를 어지립히는 것은 un 뿐입니다.
console.log(typeof un); // 'undefined' 가 기록된다.
console.log(typeof deux); // 'undefined' 가 기록된다.
console.log(typeof trois); // 'undefined' 가 기록된다.
var jsstring = 'var un = 1; console.log(un);';
eval(jsstring); // 1 이 기록된다.
jsstring = 'var deux = 2; console.log(deux);';
new Function(jsstring)(); // 2 가 기록된다
jsstring = 'var trois = 3; console.log(trois);';
(function () {
eval(jsstring);
})(); // 3 이 기록된다.
// 전역 스코프에서 변수들을 체크해 본다.
console.log(typeof un); // number 가 기록된다.
console.log(typeof un); // undefined 가 기록된다.
console.log(typeof un); // undefined 가 기록된다.
eval() 과 Function 생성자 간의 또 다른 차이는 eval() 은 유효범위 체인에 간섭을 일으킬 수 있지만 Function 은 좀더 봉인되어 있다는 점이 다릅니다.\
Function 은 어디서 실행시키든 상관없이 자신의 유효범위를 가지고 있기 때문에 지역 변수를 덜 오염시킵니다.
다음 예제는 eval() 은 그 자신의 바깥쪽 유효범위에 접근하고 수정을 가할 수 있는 반면, Function 은 그럴 수 없습니다.(Function 을 사용하는 것과 new Function 은 동일하다)
(function () {
var local = 1;
eval('local = 3; console.log(local);'); // 3 이 기록된다.
console.log(local); // 유효범위를 오염시켜 3 이 기록된다.
})();
(function () {
var local = 1;
Function('console.log(typeof local);')(); // undefined 가 기록된다.
})();