React 4 클로저
포스트
취소

React 4 클로저

우리 지난 시간에 일급 함수의 특징을 하면서 일급 함수는 함수를 return 알 수 있다 이런 특징을 보았다 그래서 그때 한 예제가

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function calualateArea(x){

    return function(width , heigth){

        return x * width * heigth;
    }
}

function clickEvent(){

    const calualateAreaOfTriangle = calualateArea(0.5);
    const calualateAreaOfSquare = calualateArea(1);

    console.log(calualateAreaOfTriangle(10 , 5))
    console.log(calualateAreaOfSquare(10 , 5))

    alert('자바 스크립트 공부 Click');
}


이렇게 반환을 했다 calualateArea 함수는 인자 하나를 받고 다른 함수를 return 하게 되는데 return 되는 함수는 최초 입력된 파라미터를 기억하고 있는 특징이 있는데 이를 우리는 클로저라고 했다

클로저 (closure)

클로저는 함수와 그 함수가 선언된 스코프에 있는 변수를 유지하는 메커니즘을 뜻합니다 이해가 안 되면 다음 예제를 봅시다

1
2
3
4
5
6
7
8
9
10
11
function outerFuction(){
    let outerVariable  = "I am from outer Function"

    return function innerFunction(){
        console.log(outerVariable)
    }
}

const call_function = outerFuction();

예를 들어서 이와 같은 함수가 있다고 하자 outerFuction 은 변수 outerVariable 선안하고 아래 속해 있는 innerFunction는 외부에서 선언된 변수를 불러서 사용하는 로직입니다 이 함수 자체는 문제는 없습니다 그 이유는 함수 안에 스코프에서 찾을 변수가 없으면 상단에 가서 가져오기 때문입니다

그리고 call_function는 outerFuction 호출해서 함수를 return 을 받게 되는데 이는 일급 함수의 특징 중 하나인 함수의 반환입니다 이때 call_function 을 호출하면 선언하지 않은 변수 outerVariable에 접근해서 사용하게 됩니다

클로저의 특징은 다음과 같습니다

  1. 외부 함수의 변수에 접근 가능 클로저 내부 함수는 자신이 정의된 외부 함수의 변수에 접근할 수 있습니다 이것은 외부 함수의 스코프를 기억하고 있습니다

  2. 변수 유지 외부 함수의 변수는 클로저에 의해서 유지됩니다 외부 함수가 실행을 마치더라도 클로저 내부 함수가 외부 변수에 접근하고 있으면 해당 변수는 계속해서 메모리에 남게 됩니다

  3. 지역변수와 전역변수 클로저는 외부 함수가 지역변수든 전역변수든 상관없이 클로저가 생성될 때의 모든 변수에 대해서 접근이 가능합니다

외부 함수의 변수에 접근 가능

1
2
3
4
5
6
7
8
9
10
11
12
function outerFuction(){
    let outerVariable  = "I am from outer Function"

    return function innerFunction(){
        console.log(outerVariable)
    }
}

const call_function = outerFuction();


이 예제를 생각해 주면 된다 즉 내부 함수는 외부 함수의 변수를 기억하고 접근할 수 있습니다 단 클로저에 의해서 생성되지 않은 것들에 대해서는 접근이 불가합니다

접근불가능한 변수

1
2
3
4
5
6
7
8
9
10
11
12
function outerFuction(){
    let outerVariable  = "I am from outer Function"

    return function innerFunction(){
        console.log(outerVariable)
    }
}

const call_function = outerFuction();

console.log(outerVariable)

이때 제일 마지막 console.log는 오류가 발생한다 그 이유는 클로저로 만들어진 변수가 아니기 때문에 현재 컨텍스트에서 outerVariable 정의된 게 아니라 클로저에 의해서 정의된 것이기 때문에 함수를 반환받아서 사용하지 않은 이상 절대로 접근할 수 없습니다

클로저 전역변수의 값 변경

1
2
3
4
5
6
7
8
9
10
11
12
13
function outerFuction(){
    let outerVariable  = "I am from outer Function"

    return function innerFunction(){
        console.log("Before OuterVariable : " , outerVariable)
        outerVariable = "I am modified by innerFunction"
        console.log("After OuterVariable : " , outerVariable)
    }
}

const call_function = outerFuction();

이 소스를 보면 외부 함수는 outerVariable에 최초로 값을 대입하고 첫 번째 innerfunction에서는 클로저의 전역변수에 접근을 합니다 그 뒤로 전역변수는 값을 변경해서 표기하고 있는 모습을 볼 수 있습니다 이렇게 되면 최초에는 외부 함숫값을 가져다 쓰고 그 뒤에는 내부 함수의 변경된 값을 불러오게 됩니다

실사용예제

  1. 비동기 작업에서의 call-back 기본적으로 promise 객체나 ajax 같은 경우는 클로저가 내포가 되어 있다 예를 들어서 다음의 예제를 보자

ajax 와 promise 의 클로저

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function click(){

    $.ajax({
        type : "get" ,
        url : "/demo",
        async : false ,
        headers : {

        },
        success : (data => {
            console.log(data);
        }) ,

        error : ( (request , status , error) => {

            console.log(request , status , error)
        })


    })

    console.log("어디가 먼저 호출될까요?")
}

지금 보면 success , error 은 click라는 함수 아래에 이와 같은 모양이 된다

1
2
3
4
success : function(data) {
    
    console.log(data)
}

이때 이 success 가 클로저 역할을 하며 data는 외부 스코프의 변수입니다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
async function fetch_function(){

    try{

    const response = await fetch('http://localhost:8080/demo' , {
        method : "GET" ,
        headers : {},
    }).then(res => {

        const status = res.status;
        if(status != 200){
            alert('서버와의 통신이 실패했습니다')
        }else{
            return res.json()
        }
    }).then( res2 => {
        console.log('res2' , res2);
    })

    //const result = await response.json();
    //console.log(result);

    }catch(error){
        console.log(error)
    }

}


다음은 promise 객체이다 이때 then 을 보게 되면

1
2
3
4
5
then ( function(res){
    ...
})

이런 모양을 띄게 되는데 이때 res는 외부 스코프의 클로저입니다

setTimeOut 의 callback

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function asyncFunction(callback){

    let data = 10;

    setTimeout( () => {
        console.log('Async operation completed');
        callback(data)
    } , 2000)

}

function callback_function(data){
    console.log('callback_function');
    console.log(data);
}


const call_function = () =>  asyncFunction(callback_function); // 이때 비동기 함수의 전달과 callback 함수의 전달을 분리해야 합니다 그렇지 않으면 바로 호출이 됩니다 

이렇게 되면 비동기 함수 시 setTimeOut 가 호출이 된 후 callBack 함수가 동작이 됩니다 이때 외부 함수에서 무엇인가 선언을 했다면 callback 함수는 이 결과를 가지고 올 수 있습니다 그리고 외부 함수에서 무엇인가 정의가 완료되어서 내부 함수로 변수를 내린 뒤 callback 함수에서는 이를 호출할 수 있습니다

오늘은 클로저에 대해서 알아보았습니다