탱구탱구 개발자 일기

우리를 괴롭히는 this가 또 나왔다. 이벤트 리스너의 경우에도 자바스크립트의 다른 this와 다르다. 이벤트 리스너 안의 this 바인딩 컴포넌트는 함수를 호출할 때 그 함수가 속한 객체의 참조이다. 이는 이벤트가 발생한 DOM 요소 객체를 말한다. 아래 예제를 통해 확인해보자.

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>eventListenerInnerThis</title>
    <script>
        function hello() {
            console.log("hello 함수:", this);
        }

        window.onload = function () {

            function Student(name) {
                this.name = name;
            }

            Student.prototype.introduce = function () {
                console.log(`소개글: ${this.name}`);
            }

            let s1 = new Student("탱구탱구");
            let button = document.getElementById("btn");
            // 리스너 정의
            button.addEventListener("click", hello, false);
            button.addEventListener("click", s1.introduce, false);
        }

    </script>
</head>
<body>
<button id="btn">버튼</button>
</body>
</html>

예제에서 버튼을 누르게 되면 클릭 이벤트에 정의된 리스너가 실행된다. 그리고 콜백 함수로 각각 hello 함수와 Student에 정의한 introduce 메서드가 호출된다.

 

자바스크립트의 기본적인 this 규칙에 따라 hello 함수 내부의 this는 window를 가리키고 indroduce 메서드는 해당 메서드가 속한 객체인 s1객체를 가리킬 것으로 예상할 수 있다. 그러나 결과는 아래와 같다.

 

이벤트 리스너 안의 this

이벤트 리스너 안의 this는 해당 이벤트가 발생한 DOM 객체를 가리키기 때문에 this는 button 객체를 참조하고 있다. 따라서 hello 함수의 this는 버튼 객체 그 자체이고 button 객체에는 name 프로퍼티 값은 빈 문자열이기 때문에 콘솔에 값이 나오지 않는다.

let button = document.getElementById("btn");
console.log(button.name); // "" : 빈 문자열

 

this가 원하는 객체를 가리키도록 설정

이렇게 이벤트 리스너를 사용할 때 그냥 사용하면 의도하지 않은 객체를 가리킬 수 있기 때문에 다음과 같은 방법을 사용해 특정 객체를 가리키도록 할 수 있다.

 

  • bind 메서드

자바스크립트 this에서도 언급했는데 Function.prototype.bind 메서드는 함수 안의 this를 메서드의 인수로 받은 객체에 바인딩한다. 예제의 스크립트 부분을 아래와 같이 수정했고 결과는 s1 객체를 this로 잘 참조하는 것을 알 수 있다.

// bind 메서드
window.onload = function () {

    function Student(name) {
        this.name = name;
    }

    Student.prototype.introduce = function () {
        console.log(`소개글: ${this.name}`);
    }

    let s1 = new Student("탱구탱구");
    let button = document.getElementById("btn");

    button.addEventListener("click", s1.introduce.bind(s1), false);
}

이벤트 리스너 this - bind 메서드

 

  • 익명 함수 안에서 실행

이벤트 핸들러나 리스너에서 익명 함수를 넘기고 그 함수 안에서 메서드를 호출하면 그 메서드의 this가 메서드를 참조하는 객체로 바인딩된다. 예제의 스크립트 부분을 아래와 같이 수정한 결과 다음과 같다.

 

window.onload = function () {

    function Student(name) {
        this.name = name;
    }

    Student.prototype.introduce = function () {
        console.log(`소개글: ${this.name}`);
    }

    let s1 = new Student("탱구탱구");
    let button = document.getElementById("btn");

    // 이벤트 리스너
    button.addEventListener("click", function (e) {
        s1.introduce();
    }, false);

    // 이벤트 핸들러
    button.onclick = function (e) {
        s1.introduce();
    }
}

이벤트 리스너 this - 익명 함수

 

  • 화살표 함수

화살표 함수를 설명할 때도 언급했지만 화살표 함수에서 this는 함수를 초기화하는 시점에 결정되고 이는 살표 함수 의 this가 화살표 함수 밖의 this를 참조한다. 화살표 함수 밖의 this는 Student 객체이다.

 

window.onload = function () {

    function Student(name) {
        this.name = name;
        this.introduce = () => {
            console.log(`소개글: ${this.name}`);
        }
    }

    let s1 = new Student("탱구탱구");
    let button = document.getElementById("btn");

    button.addEventListener("click", s1.introduce, false);
}

 

  • addEventListener 메서드의 두 번째 인수로 객체 안의 handleEvent 메서드

원래 addEventListner의 두 번째 인수는 함수가 들어가야한다. 그렇지만 자바스크립트의 모든 함수는 객체이기 때문에 당연히 함수 대신 객체를 넘길 수 있다. 그 객체에 handleEvent 메서드를 정의하면 그 메서드를 이벤트 리스너로 등록할 수 있다.

 

// addEventListner의 두번째 인수로 객체를 넘기고 handleEvent 메서드 정의하기
window.onload = function () {

    function Student(name) {
        this.name = name;
    }
    
    // 객체에 handleEvent 메서드 정의
    Student.prototype.handleEvent = function () {
        console.log(`소개글: ${this.name}`);
    }

    let s1 = new Student("탱구탱구");
    let button = document.getElementById("btn");

    button.addEventListener("click", s1, false);
}

이벤트 리스너 - handleEvent 메서드

이 글을 공유합시다

facebook twitter kakaoTalk kakaostory naver band
loading