클로저
- 클로저는 내부 함수가 외부 함수의 context에 접근할 수 있도록 하는 것이다. 이렇게 되면 외부 함수의 실행이 끝나 외부 함수가 소멸한 이후에도 내부 함수가 외부 함수의 변수에 접근할 수 있다.
- 다음 4가지는 클로저의 특징이다.
- 클로저는 객체의 메소드에서도 사용할 수 있다.
- 동일한 외부 함수 안에서 만들어진 내부 함수나 메소드는 외부 함수의 지역 변수를 공유한다.
- 똑같은 외부 함수를 공유하고 있는 내부 함수나 메소드의 결과는 서로 다를 수 있는데, 외부 함수가 실행될 때마다 새로운 지역변수를 포함하는 클로저가 생성되어 각각 완전히 독립적인 객체가 되기 때문이다.
- 클로저 내부의 변수들은 클로저 내부에서 생성된 함수나 메소드만 접근할 수 있다. 이를 이용하면 자바스크립트가 기본적으로 지원하지 않는 private가 구현 가능해진다.
function func() {
const title = "Hello";
return function () {
console.log(title);
}
}
const outter = func();
outter();
- 위 코드에서 func() 함수는 outter에 참조되며 호출된 후 소멸된다. 하지만 outter()함수가 호출되면 func 함수 내에 선언되어 있던 titlie변수가 호출되며 Hello가 출력된다. 이로서 다른 함수에 참조되면 해당 함수까지 소멸될 때까지 소멸되지 않고 존재한다는 사실을 알 수 있다.
- 클로저로 인해 문제가 주로 발생하는 곳은 반복문이다.
//반복문에서의 클로저 문제
function counter() {
const i;
for (i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
}
counter();
- 위 코드에서는 목적했던 1~10의 출력이 아니라 10이 10번 출력되는 결과가 출력된다.
- 컴퓨터의 성능은 엄청나게 좋기 때문에 첫 1초가 끝나기 전에 이미 1부터 10까지 반복을 모두 끝마치고 10을 1초마다 한 번씩 출력하기 때문에 클로저 문제가 발생하는 것이다.
- 해당 문제를 해결하기 위한 방법은 크게 두 가지가 있다.
- 새로운 스코프를 추가해 매 반복마다 값을 따로 저장하는 방식
- ES6에서 새로 추가된 방식인 블록 스코프를 이용하는 방식
//새로운 스코프를 반복마다 추가해 값을 따로 저장하는 방식
function counter() {
const i;
for (i = 0; i < 10; i**) {
(function(num) {
setTimeout(function() {
console.log(num);
}, 1000);
})(i);
}
}
counter();
- 새로운 스코프를 추가함으로서 반복문이 빠른 시간에 끝 숫자까지 도달하더라도 각 반복에 해당하는 값을 미리 저장해두어 시간이 지남에 따라 원하는 값이 출력될 수 있도록 한다.
//블록 스코프를 이용하는 방식
function counter() {
for (let i = 0; i < 10; ++i) {
setTimeout(function() {
console.log(i);
}, 1000);
}
}
counter();
- 기존의 함수 기반 스코프에서 발생했던 클로저 문제를 블록 레벨 스코프인 let으로 변경해주어 문제를 해결한다.
- let은 블록 레벨로서 해당 변수가 선언된 괄호를 넘어서지 않기 때문에 함수 기반인 var과는 달리 해당 코드가 작성된 중괄호를 기준으로 let으로 선언한 스코프를 찾은 후 점차 해당 코드가 포함된 함수로 퍼져나가게 된다.
스코프 체인
- 함수가 실행될 때 표를 찾는 것이 스코프이다.
- 자바스크립트는 기본적으로는 함수 단위로 스코프가 생성된다.
- 함수 내에 또다른 함수를 선언하면 해당 함수만의 스코프가 다시 생성되며 외부를 감싸고 있는 함수와 연결된다. 이로 인해 내부 함수에서 원하는 값이 없으면 외부로 거슬러 올라가며 스코프를 탐색하는 절차를 진행할 수 있게 된다.
- 자신이 속한 함수 내에서 해당 변수를 찾고 찾고자 하는 변수가 없다면 점차 바깥 함수로 올라가며 전역 변수까지 찾아간다. 전역 범위에까지 원하는 변수가 없다면 오류가 발생하게 된다.
function myFunction() {
var a = 1;
function innerFunction() {
var a = 2;
console.log(a);
}
console.log(a);
innerFunction();
console.log(a);
}
myFunction();
console.log(a);
- 위 코드에서의 출력은 순서대로 1, 2, 1, 오류가 된다.
- innerFunction에서 호출된 a값은 바로 근처에 있는 같은 함수 내 변수값인 2가 되며 해당 함수를 빠져나올 때 값이 증발된다.
- myFunction() 내부에서 호출된 모든 a값은 별개의 함수 안에 a를 중복 선언하지 않는 이상 1이 된다.
- 함수 밖에서 호출된 a값은 전역 범위에서 a변수가 존재하지 않기 때문에 레퍼런스 오류가 발생한다.
'프로그래밍 > JavaScript' 카테고리의 다른 글
var과 let, const (0) | 2019.08.22 |
---|---|
this (0) | 2019.08.21 |
화살표 함수 (0) | 2019.08.20 |
JavaScript (3) (0) | 2019.08.01 |
Java Script (2) (0) | 2019.07.12 |