
지금까지 스코프와 변수의 작동 메커니즘에 대해서 공부를 했고 작동 방식과 여러 관계에 대해서도 어느정도 이해했다.
그 과정에서 우리가 사용하는 JS는 대표적인 예시로 변수의 충돌을 막기 위해서 스코프 중첩을 사용한다고 했는데 이를 스코프 과다 노출 제한이라는 관점에서 좀 더 알아보기로 했다.
POLE란 principle of least exposure의 약자로 말 그대로 노출을 최소한으로 하자는 원칙을 의미한다.
정보 보안 분야에서 최소한의 권한 부여, 접근 최소화, 노출 최소화의 설계 원칙으로 사용되는 규율인 최소 권한의 원칙에 비해서 PLOE는 스코프에 집중해서 스코프마다 등록된 변수의 노출을 최소화 하는 것에 집중한 것이다.
우선 프로그램의 한 부분에서 사용할 변수를 스코프를 통해 다른 스코프에 노출시키면 발생할 수 있는 위험 사항은 뭐가 있을까?
이름 충돌 : 여러 부분에서 범용적인 이름을 가진 변수/함수를 사용하면 전역 스코프 같은 공유 스코프에서 나온 경우 이름 충돌이 발생한다. 예를들어 반복문의 i를 전역 변수를 사용하게 되면 버그가 발생할 수 있는 확률이 높아지는 것.
예기치 않은 작동 : 비공개 변수/함수를 프로그램 내부에 노출하면 다른 개발자가 의도하지 않은 방식으로 변수나 함수를 사용할 수 있다. 예를들어 숫자만 취급하는 배열을 사용하도록 했는데 외부인이 코드에 접근해 해당 배열에 문자열 혹은 불리언 값을 사용하는 경우.
의도하지 않은 종속성 : 변수나 함수가 불필요하게 노출되면 다른 개발자가 비공개로 처리된 변수/함수를 사용하고 여기에 의존성이 생길 수 있다. 예를들어 내가 만든 라이브러리 혹은 컴포넌트를 다른 개발자가 사용할 때 라이브러리 내부에서만 사용하려고 만든 변수를 사용하면서 외부 코드(라이브러리 사용자가 만든 코드)에 의존성이 생기면 추후 라이브러리를 리팩터링하기 쉽지 않다.
이러한 이유 때문에 POLE는 변수/함수 스코프 지정 시 최소한의 것만 노출하고 나머지는 가능한 비공개로 유지하도록 제안한다.
그렇다면 노출된 변수는 무엇이고 이걸 어떻게 숨길 수 있는지 예시를 한 번 보면서 알아보자.
var cache = {};
function factorial(x) {
if (x < 2) return 1;
if (!(x in cache)) {
cache[x] = x * factorial(x - 1);
}
return cache[x];
}
factorial(6) // 720
위의 함수는 팩토리얼(!)을 구현한 코드이다.
특이점은 연산 속도를 증가시키기 위해서 메모리에 이미 계산된 값들을 저장하고 필요에 따라서 추가적인 계산만 실행하도록 했다.
하지만 문제점은 위의 연산에서 사용된 cache라는 변수는 factorial 함수 내부에서만 사용되는 변수이기 때문에 비공개 변수로 처리되어야 하는데 전역 혹은 외부 스코프에 존재한다.
이를 POLE 규칙에 맞춰서 개선한 코드를 보자.
function hideTheCache () {
var cache = {};
function factorial (x) {
if (x < 2) return 1;
if (!(x in cache)) {
cache[x] = x * factorial(x - 1);
}
return cache[x];
}
return factorial;
}
var factorial = hideTheCache();
factorial(6) // 720
위의 코드를 보면 기존에 스코프가 나뉘어져 있던 cache 변수와 factorial 함수를 hideTheCache라는 함수 스코프로 한 번 더 감싸주었다.
이러한 방식은 직관적이고 단순하지만 매번 새로운 함수와 스코프를 만들기란 번거롭기 때문에 이런 경우에는 함수 표현식과 함수 즉시 호출을 사용해서 좀 더 효율적인 코드를 구현할 수 있다.
var factorial = (function () {
var cache = {};
function factorial (x) {
if (x < 2) return 1;
if (!(x in cache)) {
cache[x] = x * factorial(x - 1);
}
return cache[x];
}
return factorial;
})()
factorial(6) // 720
다만 주의할 점이라면 IIFE도 엄연한 하나의 함수이고 스코프 중첩이 발생하게 된다.
떄문에 this의 바인딩이 바뀌게 되고 break, continue 문은 IIFE의 스코프 경계를 넘을 수 없기 때문에 이들로 외부 스코프 제어문을 통제할 수 없게 된다는 점을 주의하자.