시스템아 미안해

Chapter 3 - Item 27. 문자열 보다 클로저로 코드 캡슐화하기를 선호하라 본문

책/Effective JavaScript

Chapter 3 - Item 27. 문자열 보다 클로저로 코드 캡슐화하기를 선호하라

if else 2025. 8. 10. 15:49

과거 자바스크립트 API 중 일부는 문자열로 코드를 받아서 실행하는 기능

(eval, new Function, setTimeout의 문자열 인자 등) 을 제공했다.

setTimeout("doSomething()", 1000);

new Function("a", "b", "return a + b;")

element.setAttribute("onclick", "alert('clicked')");

 

이 방식은 내부적으로 eval 과 유사하게 동작한다.

즉, 문자열을 런타임에 파싱·컴파일해서 실행하므로 아래와 같은 문제가 있다.

 

 

1. 보안 취약점 (XSS)

 

  • 문자열로 코드를 만들면 외부 입력이 그대로 실행될 수 있다.
  • 악의적인 스크립트를 심으면 그대로 브라우저에서 돌아감

 

2. 성능 저하

매번 문자열을 파싱 → AST(구문 트리)로 변환 → 실행해야 해서 느림.

 

3. 스코프 예측 불가

  • 문자열로 실행된 코드는 정의 당시의 스코프를 기억하지 않는다.
  • 항상 전역 컨텍스트나 새로운 실행 컨텍스트에서 실행됨.
  • 결과적으로 지역 변수나 this를 전혀 쓸 수 없음.
let msg = "Hello";
setTimeout("console.log(msg)", 1000); // ReferenceError: msg is not defined
  1.  
 

 

그리하여 책에서는 다음과 같이 권장한다.

  • 문자열로 코드 전달하지 말 것
  • 클로저(함수)로 감싸서 전달할 것 -> 외부 변수를 그대로 캡처하고 실행 환경을 보존할 수 있음
setTimeout(function () {
  console.log('Hello');
}, 1000);

여기서 말하는 "클로저"는 정의 당시의 스코프(변수 환경)를 기억하는 함수를 뜻한다.
이렇게 하면 함수가 정의될 때 참조한 지역 변수나 this를 실행 시점에도 그대로 쓸 수 있다.

 

 


 

 

 

ES6 이후 화살표 함수로 클로저를 더욱 간결하게 작성 가능하다.

// ES5
setTimeout(function () {
  console.log(msg);
}, 1000);

// ES6+
setTimeout(() => console.log(msg), 1000);

화살표 함수는 자신만의 this를 만들지 않고 바깥 스코프의 this를 그대로 사용하기 때문에,
이벤트나 비동기 콜백에서 this가 꼬이는 문제도 줄여준다.

 

 

 

 

  • eval 계열 API와 문자열 실행은 전면 금지
  • 클로저 기반 함수 전달이 기본 원칙
  • 문자열 실행이 필요한 경우는 없다고 가정하고 설계