JS에서 스코프와 클로져

이윤환·2021년 5월 29일
0

javascript / 문법

목록 보기
1/1

스코프와 클로져

js에서 함수를 더 심도있고 활용도를 올리고 싶으면 클로져를 알아야 하며, 클로져를 이해하기 위해선 먼저 스코프에 대한 이해가 필요하다.

스코프란 간단하게 유효범위라고 생각하면 되는데 모든 프로그래밍에서도 당연히 사용되는 기본적인 개념이지만 보통 언어와 js 에서의 유효범위는 조금 다르다.

아직 공부중이고, 이해가 완벽하지 않아서 내가 이해한대로 적을것이다.

1. 스코프 (Scope)

앞서 말한대로 유효범위라고 생각하면 된다.
더 자세히는 변수 접근(reference) 규칙에 따른 유효범위이다.
스코프는 크게 '전역 스코프(Global Scope)'와 '지역 스코프('Local Scope')' 이렇게 두가지로 나뉜다.

-전역 스코프(Global Scope): 함수 전체에서 참조되는 것을 의미한다. 어느곳에서도 참조가 가능하다.
-지역 스코프(Local Scope): 정의된 함수 내부에서만 사용 가능하며 함수 외부에서는 참조가 불가능하다.

지역 스코프에서 선언한 변수의 우선순위가 더 높지만 내부에서만 사용이 가능하다는 점이고 전역 스코프에서 선언한 변수는 어디서든 사용이 가능하다는 점을 이해해두면 된다.

이 개념을 이해하기 전까지는 var 은 가급적 사용하지 말라는 말을 반의 반도 이해를 못했었는데 var 로 선언한 변수는 외부 내부 스코프 어디서든 사용이 가능하다는 것을 깨달은 후에는 let 혹은 const 만을 사용하고 있다.

2. 클로져 (Closure)

위에서 스코프에 대해서 대략적인 설명을 했다. 그러면 클로져는 무엇인가 먼저 MDN 에서는
'함수와 함수가 선언된 어휘적(lexical) 환경의 조합을 말한다. 이 환경은 클로저가 생성된 시점의 유효 범위 내에 있는 모든 지역 변수로 구성된다.' 라고 나와있다.

자 이로써 우리가 아무리 한국인이고(혹은 한국에서 오래 살았어도) 한국어로 나와있는 글이어도 모든 한국어를 이해할 수 없다는 것을 깨달았다.

그래도 굴하지 말고 천천히 살펴보자
먼저 MDN을 읽어보자

function init() {
    var name = "Mozilla"; // name is a local variable created by init
    function displayName() { // displayName() is the inner function, a closure
        alert (name); // displayName() uses variable declared in the parent function    
    }
    displayName();    
}
init();

위 코드를 실행하면 displayName() 함수 내의 alert()문이 부모 함수에서 정의한 변수 name의 값을 출력한다. (ex) alert: Mozilla) 우리는 위의 스코프에서 배운대로 displayName() 함수의 외부 스코프에서 선언된 name이라는 변수를 사용할 수 있다는 것을 알았다. 바로 이게 어휘적(lexical) 범위의 예시이다. 우리는 중첩된 함수는 외부범위에서 선언한 변수에도 접근이 가능하다는 것을 깨달았다.

그럼 다음 예제를 보자

function makeFunc() {
  var name = "Mozilla";
  function displayName() {
    alert(name);
  }
  return displayName;
}

var myFunc = makeFunc();
//myFunc변수에 displayName을 리턴함
//유효범위의 어휘적 환경을 유지
myFunc();
//리턴된 displayName 함수를 실행(name 변수에 접근)

아마 이전에 나온 예시에 비해서 직관적으로 알아보기 힘들것이다. (한 눈에 알아본다면 당신은 차기 폰 노이만)
이 코드는 이전에 나온 예시와 완전 동일한 결과가 실행된다. 하지만 차이는 바로 displayName() 함수가 실행되기 전에 makeFunc() 함수로부터 리턴되어 myFunc라는 변수에 저장된다는 것이다.

대부분의 프로그래밍 언어에서는 함수안의 지역 변수들은 그 함수가 처리되는 동안에만 존재한다. 즉 makeFunc()의 실행이 끝나면 (displayName 함수가 리턴된 이후에는) name 변수에 더 이상 접근이 어렵다 라고 예상되는게 정상이다.

하지만 내가 맨 위에서 언급했듯이 js에서 클로져는 경우가 다르다.
js에서는 함수를 리턴하고, 리턴하는 함수가 클로져를 형성하기 때문이다. 다시 말하지만 클로져는 '함수와 함수가 선언된 어휘적(Lexical) 환경의 조합'이다.
즉 mkeFunc가 실행될 때 생성된 displayName함수의 인스턴스에 대한 참조이다.
dispalyName의 인스턴스는 변수 name이 있는 어휘적 환경에 대한 참조를 유지하므로 myFunc가 호출될 때 변수 name은 사용할 수 있는 상태로 남게 되어 "Mozilla" 가 alert에 전달된다.

그럼 왜 사용할까 이렇게 복잡하고 어려운 개념인데 굳이 알아야 할까...?

알면 좋다. 외부에서 내부에 접근이 불가능 하다는 규칙 하나로도 내부 변수에 대한 간섭을 없앰으로써 실수로 변수에 값을 할당하게 되어 발생할 이슈들이 적어질테고 간섭이 불가능하다는것은 함수 그자체가 독립적이게 되어 함수의 모듈화에 유리하다는 것이다.

분명 이 외에도 활용도는 무궁무진할 것이다. 하지만 내 부족한 머리로는 아직 멀었다. 하지만 몇 번씩 비슷한 예제나 직접 코드를 작성하면서 오류를 발견하고 완성된 스크립트를 보면서 습득해나갈게

profile
나는 이윤환

0개의 댓글