함수와 그 함수가 선언됐을 당시의 렉시컬 환경과의 조합(combination)
실행컨텍스트
:JS 엔진
이 동일한 환경에 있는 코드를 실행하기 위해
필요한 정보(환경 정보)를 수집하는데, 이러한 정보들을 모아놓은 객체
variableEnvironment
: 식별자 정보, 외부환경 정보 초기화LexicalEnvironment
: 식별자 정보, 외부환경 정보 수집ThisBinding
: this 바인딩실행 컨텍스트가 활성화되면 outer-LexicalEnvironment
에서 자신이 선언된 스코프의 LexiclEnvironment
를 참조 복사한다.
모든 함수는 [[Environment]]
라는 숨김 프로퍼티를 갖는데,
이곳에 참조가 저장된다.
해당 실행 컨텍스트의 렉시컬 환경(environmentRecord)에 식별자 정보가 없을 경우, outer-LexicalEnvironment
에서 참조 복사된 상위 스코프의
LexicalEnvironment
에서 식별자 정보를 찾는다.
const outer = function () {
let a = 1;
const inner = fuction () {
console.log(++a);
};
inner();
};
outer();
const outer = function () {
let a = 1;
const inner = function () {
return ++a;
};
return inner();
};
const outer2 = outer();
console.log(outer2);
결과적으로 outer2
엔 inner 함수를 참조.
environmentRecord
: 비어있음outer-LexicalEnvironment
: outer L.E 참조가비지 컬렉터
가 도달 가능성을 판단하고 수집 대상에 포함 X.
어떤 함수에서 선언한 변수를 참조하는 내부함수에서만 발생하는 현상
👇🏻
외부 함수의 LexicalEnvironment
가 가비지 컬렉팅되지 않는 현상
👇🏻
어떤 함수 A에서 선언한 변수 a를 참조하는 내부함수 B를 외부로 전달할 경우,
A의 실행 컨텍스트가 종료된 이후에도 변수 a가 사라지지 않는 현상.
외부로 전달
: 지역 변수를 참조하는 내부 함수를 외부에 전달
1. 리턴
2. 콜백으로 전달
(function () {
let a = 0;
let intervalId = null;
const inner = function () {
if (++a >= 10) {
clearInterval(intervalId);
}
console.log(a);
};
intervalId = setInterval(inner, 1000);
})();
지역변수를 참조하는 내부 함수: inner 함수
지역변수: a
, intervalId
⭐️ setTimeout
, setInterval
: window의 메서드 (별도의 외부 객체)
(function () {
let count = 0;
let button = document.createElement('button');
button.innerText = 'click';
button.addEventListener('click', () => {
console.log(++count, 'times clicked');
});
document.body.appendChild(button);
})();
지역변수를 참조하는 내부 함수: addEventListener의 콜백 함수
지역변수: count
⭐️ addEventListener
: DOM의 메서드 (별도의 외부 객체)
가비지 컬렉터는 어떤 값의 참조 카운트가 0
이 될 경우 수거 대상으로 지정한다.
클로저로 인해 계속해서 지역변수를 참조하고 있을 경우,
메모리가 소모되므로 참조 카운트를 0으로 만들자!
참조형이 아닌 기본형 데이터 할당.
const outer = (function () {
let a = 1;
let inner = function () {
return ++a;
};
return inner;
})();
console.log(outer());
console.log(outer());
outer = null; // ⭐️ 참조 해제
outer 식별자의 inner 함수 참조를 끊음.
(function () {
let a = 0;
let intervarId = null;
const inner = function () {
if (++a >= 10) {
clearInterval(intervalId);
inner = null; // ⭐️ 참조 해제
}
console.log(a);
};
intervalId = setInterval(inner, 1000);
})()
inner 식별자의 함수 참조를 끊음.
(function () {
let count = 0;
let button = document.createElement('button');
button.innerText = 'click';
const clickHandler = function () {
console.log(++count, 'times clicked');
if (count >= 10) {
button.removeEventListener('click', clickHandler);
clickHandler = null; // ⭐️ 참조 해제
}
}
button.addEventListener('click', clickHandler);
document.body.appendChild(button);
})();
EventListener
는 보통 콜백함수를 handler로 쓰는데,
무명 콜백 함수를 유명함수로 바꿔 null | undefined
을 할당할 수 있도록 만들기.
외부로 전달
: 지역 변수를 참조하는 내부 함수를 외부에 전달
const fruits = ['apple', 'banana', 'peach'];
const $ul = document.createElement('ul');
fruits.forEach(fruit => { // 콜백함수 A
const $li = document.createElement('li');
$li.innerText = fruit;
$li.addEventListener('click', () => { // 콜백함수 B
alert('your choice is' + fruit);
});
$ul.appendChild($li);
});
document.body.appendChild($ul);
forEach
의 콜백함수(A)로 순회forEach
가 순회되는 것과 별개로,addEventListener
의 콜백함수 B가 클릭 이벤트마다 실행.const fruits = ['banana', 'apple', 'orange'];
const $ul = document.createElement('ul');
const alertFruit = fruit => // 공통함수로 쓰기 위해 변수에 담음
alert('your choice is' + fruit);
fruits.forEach(fruit => { // 콜백함수 A
const $li = document.createElement('li');
$li.innerText = fruit;
$li.addEventListener('click', alertFruit); // ⭐️ 인자 바꿔주기
$ul.appendChild($li);
});
document.body.appendChild($ul);
alertFruit(fruits[1]);
고차함수
: 함수를 인자로 받거나, 함수를 리턴하는 함수
const alertFruitBuilder = fruit => {
return () => alert('your choice is' + fruit);
};
// 함수를 리턴
fruits.forEach(fruit => { // 콜백함수 A
const $li = document.createElement('li');
$li.innerText = fruit;
$li.addEventListener('click', alertFruitBuilder(fruit)); // 리턴된 함수가
$ul.appendChild($li);
});
document.body.appendChild($ul);
alertFruitBuilder
는 함수를 리턴.
👇🏻
리턴된 함수는 EventListener의 콜백함수로 사용됨.
👇🏻
언젠가 클릭 이벤트가 발생하면, alertFruitBuilder
실행컨텍스트가 활성화되며
인자로 넘어온 fruit
를 outer-LexicalEnvironment
에 의해 참조.