자바스크립트는 어휘적 환경(Lexical Environment)이 존재한다.
렉시컬 환경이란 특정 코드가 작성, 선언된 환경을 의미하며, 객체이다.
렉시컬 환경을 왜 알아야하나?
내가 사용하고자 하는 변수, 함수 등이 어떤 렉시컬 환경에 속해있는지에 따라 이용 가능한 변수가 달라 지기 때문이다.
어떤 변수나 함수의 값은 이를 '어디에서 호출 했는지' 가 아니라, '어디에서 선언 했는지' 즉 렉시컬 환경이 어디인지에 따라서 결정된다. 이를 Lexical scoping이라 한다.
add3라는 함수의 입장에서 생각해볼 때, 자신의 스코프 내에 있는 y라는 변수는 인자로 받았고 해당 스코프 내에 갇혀있지만, x라는 변수는 해당 스코프 내에 갇혀있지 않다.
이때의 x를 자유 변수(Free variable), y를 묶인 변수(Bound variable) 라고 부른다.
따라서 클로저는 자유 변수를 기억하여 생성 이후에도 계속 접근이 가능하도록 스코프내로 가져와 닫는다.
function sayName() {
const name = 'kyle';
console.log(name);
}
sayName(); //kyle
console.log(name); //error
위의 코드에서 sayName이 끝나면 sayName의 렉시컬 환경에 있던 name 변수는 접근할 수 없다.
name 변수에 접근하고 싶다면 클로저를 사용한다.
function outer() {
const name = 'kyle';
return function inner() {
console.log(name);
};
}
const getKyle = outer();
getKyle(); //kyle
전역 변수를 줄일 수 있다.
예를 들어 count를 세는 함수가 있다고 해보자.
let count = 0;
function cilck() {
count++;
return count;
}
click();
위와 같이 count를 전역변수로 사용해줘야 count값을 계속 증가 시켜줄 수 있다. 이럴 경우 클로저를 이용해 전역 변수를 없앨 수 있다.
function cilck() {
let count = 0;
return function () {
count++;
return count;
};
}
const onClickButton = click();
onClickButton();
const newTag = function (open, close) {
return function (content) {
return open + content + close;
};
};
const bold = newTag('<b>', '</b>');
const italic = newTag('<i>', '</i>');
console.log(bold(italic('This is my content!')));
//<b><i>This is my content!</i></b>