울면서개발하기
JAVA SCRIPT / NEXACRO

넥사크로에서 eval 없이 컴포넌트에 동적으로 접근하기

· 2026년 10월 25일 다시 씀

결론부터. 이름을 조합해서 컴포넌트를 찾는 용도라면 eval 은 필요 없다. 브라켓 표기법 obj["이름" + i] 으로 바꾸면 된다.

// 전
eval("this.div_row" + i).set_visible(false);

// 후
this["div_row" + i].set_visible(false);

문제: 화면 스크립트 곳곳의 eval

넥사크로 프로젝트에서는 아래 같은 코드를 자주 본다. 제가 있던 프로젝트에는 이런 사용처가 900건이 넘었다.

for (var i = 1; i < 5; i++) {
  eval("this.div_main.form.div_frame.form.div_row" + i).set_visible(false);
  eval("this.div_main.form.div_frame.form.div_row" + i + ".form.edt_title").set_value("");
  eval("this.div_main.form.div_frame.form.div_row" + i + ".form.edt_score").set_value("");
}

외부 감리나 정적 분석 도구는 eval 을 동적 코드 실행(CWE-95) 위험으로 지적한다. 문자열에 바깥 입력이 섞이면 임의 코드가 실행될 수 있고, 그렇지 않더라도 읽기 어렵고 느리다.

해결 1: 브라켓 표기법

자바스크립트 객체의 속성은 . 뿐 아니라 [문자열] 로도 접근할 수 있다. 넥사크로의 Form 은 자바스크립트 객체이고, 화면에 올린 컴포넌트는 Form 의 속성이므로 그대로 쓸 수 있다.

this.Button00;        // 점 표기법
this["Button00"];     // 브라켓 표기법 — 같은 객체

this.ds_main.setColumn(0, "A", "1");
this["ds_main"]["setColumn"](0, "A", "1"); // 위와 같다

위의 반복문은 이렇게 바뀐다. 같은 경로를 매번 다시 찾지 않아도 되어 더 짧아진다.

var frame = this.div_main.form.div_frame.form;

for (var i = 1; i < 5; i++) {
  var row = frame["div_row" + i];
  row.set_visible(false);
  row.form.edt_title.set_value("");
  row.form.edt_score.set_value("");
}

"div_main.form.div_row1" 처럼 점이 들어간 경로 문자열을 받아야 한다면, 점으로 나눠서 한 단계씩 브라켓으로 따라가는 함수를 하나 두면 된다(ES5 문법이라 구버전에서도 동작한다).

this.fn_lookup = function (path) {
  return path.split(".").reduce(function (obj, key) {
    return obj == null ? undefined : obj[key];
  }, this);
};

this.fn_lookup("div_main.form.div_frame.form.div_row" + i).set_visible(false);

해결 2: 넥사크로의 components 속성

넥사크로는 eval 대신 쓸 수 있는 속성으로 components 를 제공한다(all, objects 같은 속성도 있다). 공식 도움말 설명은 “Form 에 등록된 모든 컴포넌트를 갖고 있는 읽기전용 속성”이다. Collection 방식으로 접근할 수 있어서 이름과 인덱스, length 를 모두 쓸 수 있다.

this.components["Button00"];  // 이름으로
this.components[0];           // 인덱스로

for (var i = 0; i < this.components.length; i++) {
  trace(this.components[i].name);
}

이름을 알고 접근하는 경우에는 브라켓 표기법과 결과가 같다. 이름을 모른 채 화면의 컴포넌트를 전부 돌아야 할 때 components 가 쓸모 있다. 배열처럼 생겼지만 진짜 배열은 아니므로(유사 배열) map, forEach 같은 배열 메서드가 바로 되지 않을 수 있다. for 문과 length 로 도는 것이 안전하다.

new Function 은 대안이 아니다

eval 을 피하려고 new Function("return " + code)() 로 바꾸는 경우가 있다. 이렇게 하면 eval 이라는 글자는 사라지지만, 문자열을 코드로 실행한다는 점은 같다. 정적 분석 도구도 new Function, 문자열을 넘기는 setTimeout 을 같은 종류로 본다. 차이는 new Function 으로 만든 함수가 지역 변수를 보지 못하고 전역 범위에서 실행된다는 것뿐이다.

또 일부 버전의 넥사크로 스튜디오에서는 new Function 을 쓰면 제너레이트가 되지 않는다는 이야기도 들었다(직접 확인하지는 못했다).

정리하면 다음 순서로 고르면 된다.

  1. 객체·컴포넌트 접근이 목적이면 → 브라켓 표기법
  2. 화면 전체를 순회해야 하면 → components
  3. 정말로 문자열 식을 실행해야 하면(사용자 입력이 아니라 개발자가 쓴 식일 때만) → 그 사실을 감리 측에 설명할 수 있게 한곳에 모아 둔다

다시 쓰며 바로잡은 점

  • 원문은 “어쩔 수 없을 때는 new Function 으로 회피”를 권했는데, new Function 도 문자열을 코드로 실행하므로 보안상 eval 과 같은 지적 대상이다. 대안 목록에서 뺐다.
  • 원문 예제의 setColum 오타를 setColumn 으로 고쳤다.
  • 점이 들어간 경로 문자열을 eval 없이 따라가는 함수를 추가했다.