JavaScript | 스코프(Scope)와 클로저(Closure)는 무엇일까?

AEHEE·2022년 11월 13일
0

JavaScript

목록 보기
3/10
post-thumbnail

👩🏻‍💻 스코프(Scope), 클로저(Closure)

📌 스코프(Scope)

ES5의 스코프는 함수 레벨 스코프까지 지원 했었는데 ES6부터는 블록 레벨의 스코프를 지원해 let, const키워드를 통해 블록 레벨 스코프의 사용이 가능해졌다.

// ES5
function apple() {
	if(ture) {
    	var color = 'red';
    }
  	console.log(color); //red
}

// ES6
function apple() {
	if(ture) {
    	let color = 'red';
      console.log(color); //red
    }
  	console.log(color); //not defined
}

예제를 보면 ES5의 var키워드는 함수 레벨 스코프를 갖고 ES6의 let키워드는 블록 레벨 스코프를 가지고 있다.

렉시컬 스코프(Lexical scope)

스코프는 함수를 호출할 때가 아니라 선언할 때 생긴다. 함수를 어디에서 호출하였는지는 스코프 결정에 아무런 의미를 주지 않는다.

var name = 'aehee';

function a(name) {
  console.log(name);
}
function b() {
  a(name);
}

function c() {
  var name = 'autumn';
  a(name);
}

b(); // aehee
c(); // autumn

해당 코드를 보면 쉽게 이해할 수 있다.

호이스팅

변수를 선언하고 포기화 했을 때 선언 부분이 최상단으로 끌어올려지는 현상을 호이스팅이라고 한다. 함수 표현 식이 아닌 함수 선언식일 때는 식이 통째로 끌어올려진다.

isName();
isFood();

const isName = function(){
  console.log('aehee');
}

function isFood(){
  console.log('coffee');
}

위 코드를 보면 isName은 Context에 아직 대입되기 전이어서 에러가 발생한다.

📌 클로저(Closure)

클로저는 반환된 내부 함수가 자신이 선언됐을 때의 환경(Lexical environment)인 스코프를 기억하여 자신이 선언됐을 때의 환경(Scope) 밖에서도 호출되어도 그 환경(Scope)에 접근할 수 있는 함수를 말한다.
쉽게 말하자면! 내부 함수는 외부함수의 지역변수에 접근할 수 있는데 외부함수의 실행이 끝나서 외부함수가 소멸한 이후에도 내부 함수가 외부함수의 변수에 접근할 수 있다
클로저의 핵심은 스코프를 이용해서 변수의 접근 범위를 닫는(폐쇄) 것에 있다.
클로저가 가장 유용하게 사용되는 상황은 현재 상태를 기억하고 변견된 최신 상태를 유지하는 것이다.

클로저의 장점은?

  1. 데이터를 보존할 수 있다.
  2. 클로저 모듈 패턴을 사용해 객체에 담아 여러 개의 함수를 리턴하도록 만든다. (캡슐화)
  3. 클로저를 통해 데이터와 메소드를 묶어다닐 수 있기에 클로저는 모듈화에 유리하다.

기본적으로 잘 쓰이는 예제를 가져왔다.
클릭을 할 때 마다 count가 증가하는 함수가 있다고 가정해보자.

const addButton = document.querySelector('button');

addButton.addEventListener('click', handleClick);

let count = 0;
function handleCilck() {
  count++
  return count;
}

위 같은 경우에는 count를 전역변수로 사용해줘야 count가 증가한다.
이럴경우 클로저를 사용할 수 있다.

const addButton = document.querySelector('button');

addButton.addEventListener('click', handleClick());

function handleCilck() {
  let count = 0;
  return function () {
    count++
    return count;
  }
}

이렇게 작성해주면 handleClick의 Lexical environment를 참조하는 함수를 addButton의 콜백함수로 이용해 전역객체 없이 구현할 수 있다.

유의!

function outer() {
  let name = 'lee';
  if (true) {
    let city = 'seoul';
    return function inner() {
      console.log(city);
    };
  }
}

여기서 객체를 확인해보면 city는 클로저가 아니다.
클로저는 내부에 선언된 함수가 외부함수의 지역변수를 사용해 줬을 때만 클로저라고 한다.
inner 함수에도 클로저를 사용하고 싶으면 name 변수를 사용해줘야 한다.

function outer() {
  let name = 'lee';
  if (true) {
    let city = 'seoul';
    return function inner() {
      console.log(name);
    };
  }
}

outer의 객체를 확인 했을 때 closure에 name이 들어온다.

profile
UI개발자에서 FE개발자로 한걸음 더!

0개의 댓글

관련 채용 정보