본문 바로가기

Front End/Javascript

[JavaScript] 콜백(Callback) 함수 5(this 문제점)

 이처럼 단순히 함수의 파라미터에 함수를 넘겨주면 끝이라 생각하기 쉽지만  자바스크립트의 콜백 함수 이용에는 몇가지 조심해야 할 주의점이 있습니다.

 

다음을 보겠습니다. 함수에서 this는 무엇일까요?

       function fn1() {
            console.log(`선억적 함수 this : ${this}`);
            console.log(this);
        }
        let fn2 = () => {
            console.log(`화살표 함수 this : ${this}`);
            console.log(this);
        }
        // 함수에서 this는 기본적으로 전역객체의 window로 정해져 있습니다.
        fn1();
        fn2();

 

실행 결과를 보면 다음과 같이 window객체를 나타냅니다.

 

그렇다면 전달되는 콜백함수가 this를 사용하고 있다면 문제가 생깁니다.

다음을 보겠습니다.

           let user = {
            signUp: '2024-08-31',
            name: '무명',
            age : 22,
            setName: function (name) { // 메서드 선언
                this.name = name;
            },
            setSignUp: function (signUp) { // 메서드 선언
                this.signUp = signUp;
            },
            setAge(age){ // 메서드 축약형
                this.age = age;
            },
            show(){ // 메서드 축약형
                return `${this.name}씨(가입일 : ${this.signUp}, ${this.age}세)`;
            }
        }
        console.log(user.show());
       
        function setName(name, callback){
            callback(name);
        }
        function setSignUp(signUp, callback){
            callback(signUp);
        }
        function setAge(age, callback){
            callback(age);
        }
       
        setName('한사람',  user.setName);
        setSignUp('2024-10-01', user.setSignUp);
        setAge(33, user.setAge);
        console.log(user.show());
       
        // 왜 바뀌지 않았을까?
        console.log(`user.name = ${user.name}`);
        console.log(`user.name = ${user.signUp}`);
        // 콜백함수에서 this는 전역 객체이다.
        console.log(`window.name = ${window.name}`);
        console.log(`window.name = ${window.signUp}`);

 

결과입니다. 에러는 아니지만 원하는 값은 변경되지 않았습니다.

 

이 문제를 해결하려면 어떻게 해야 할까요? 함수를 다음과 같이 변경해 줘야 합니다.

        // 이것을 해결하여면 다음과 같이 해야 한다.
        function setName(name, callback, data){
            callback.call(data, name);
        }
        function setSignUp(signUp, callback, data){
            callback.apply(data, [signUp]);
        }
        function setAge(age, callback, data){
            callback.bind(data)(age);
        }

        setName('이세상',  user.setName, user);
        setSignUp('2024-11-01', user.setSignUp, user);
        setAge(44, user.setAge, user);
        console.log(user.show());

 

다음과 같이 user객체의 내용이 변경되었습니다.

 

 

콜백 함수 this 해결 방안

따라서 콜백 함수 내의 this를 보호할 수 있도록 콜백 함수를 만들어야 합니다.

해결 방안으로는 call() 과 apply() 그리고 bind()를 사용하여 this 를 보호할 수 있습니다.

call() : 첫 번째 인자로 this 객체 사용, 나머지 인자들은 , 로 구분해서 전달합니다.
apply() : 첫 번째 인자로 this 객체 사용, 나머지 인자들은 배열 형태로 전달 합니다.
bind() : 함수가 가리키는 this만 바꾸고 호출하지는 않는 겁니다. 정확히 말하면 this를 정의하고 나서 그 함수를 복사해 새로운 함수를 만들어 리턴 하는 겁니다.


해결방법은 콜백 함수 내에서 call(), apply(), bind() 메서드를 통해 콜백 함수가 참조할 객체를 지정해주면 됩니다.

 

        function 함수(변경값, callback함수, 변경객체){
            callback함수.call(변경객체, 변경할 값);
            또는
            callback함수.apply(변경객체, [변경할 값]);
            또는
            callback함수.bind(변경객체)(변경할 값);
        }

 

ex05.html 파일을 다음과 같이 만듭니다.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<!DOCTYPE html>
<html lang="ko">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>콜백함수 내의 this 문제점</title>
    <script>
        let user = {
            signUp: '2024-08-31',
            name'무명',
            age : 22,
            setName: function (name) { // 메서드 선언
                this.name = name;
            },
            setSignUp: function (signUp) { // 메서드 선언
                this.signUp = signUp;
            },
            setAge(age){ // 메서드 축약형
                this.age = age;
            },
            show(){ // 메서드 축약형
                return `${this.name}씨(가입일 : ${this.signUp}, ${this.age}세)`;
            }
        }
        console.log(user.show());
        
        function setName(name, callback){
            callback(name);
        }
        function setSignUp(signUp, callback){
            callback(signUp);
        }
        function setAge(age, callback){
            callback(age);
        }
        
        setName('한사람',  user.setName);
        setSignUp('2024-10-01', user.setSignUp);
        setAge(33, user.setAge);
        console.log(user.show());
        
        // 왜 바뀌지 않았을까?
        console.log(`user.name = ${user.name}`);
        console.log(`user.name = ${user.signUp}`);
        // 콜백함수에서 this는 전역 객체이다. 
        console.log(`window.name = ${window.name}`);
        console.log(`window.name = ${window.signUp}`);
        
        // 이것을 해결하여면 다음과 같이 해야 한다.
        function setName(name, callback, data){
            callback.call(data, name);
        }
        function setSignUp(signUp, callback, data){
            callback.apply(data, [signUp]);
        }
        function setAge(age, callback, data){
            callback.bind(data)(age);
        }
 
        setName('이세상',  user.setName, user);
        setSignUp('2024-11-01', user.setSignUp, user);
        setAge(44, user.setAge, user);
        console.log(user.show());
 
    </script>
</head>
 
<body>
    <div id="result"></div>
</body>
 
</html>
cs

 

 

 

실행 결과 입니다.