ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • javascript this와 bind
    Knowledge/javascript 2019. 9. 15. 13:46
    반응형

    생성자 패턴을 활용하다 보면 javascript의 this가 내 맘 같지 않은 상황을 자주 마주 한다.

    예를 들자면 이런 것이다.

     

    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
    function promotionObj(id) {
        
            this.registerEvents(id);
            
    }
     
    promotionObj.prototype = {
            
            // 등록 이벤트
            registerEvents : function(id){
                // 뒤로 가기 버튼
                var backBtn = document.querySelector(".btn_back");
                
                backBtn.addEventListener("click",function(){
                    this.backToDetail(id);
                });
            },
            
            
            // 상세보기로 이동
            backToDetail : function(id){
                location.href = "/reservation/detail?id="+id;
            }    
            
    }
     
    document.addEventListener('DOMContentLoaded'function() {
        
        // promotion 객체 생성
        promotion = new promotionObj(initObj.id);
        
    });

     

    'promotion 객체를 생성할 때 객체내의 registerEvents 함수를 실행하여

    backBtn에 backToDetail을 실행하는 클릭 이벤트 리스너를 달아라' 라는 내용의 코드인데

    실행해보면 의도대로 작동되지 않는다.

     

    원인을 찾아보면 this.backToDetail(id); 부분이 문제다.

    분명 같은 객체 안에 있으니 this.bakcToDetail()이라고 하면 같은 객체안에 있는 backToDetail 함수를 가르킬 것 같지만 console.log를 활용해 확인하면 this가 undefinded라고 출력되기 떄문이다. 왜일까?

     

    이는 javascript에서 this의 특성때문이다.

     

    javascript의 this는 현재 실행 문맥에 따라 결정된다. 즉 해당 메소드의 호출자가 누구인지에 따라 this가 정해진다는 것.

    registerEvents() 를 예로 들자면 이 메소드를 호출하는 것은 명백히 promotionObj 객체기 때문에

    this를 사용했을 때 이 this가 promotionObj를 가르키고 있음을 알고 의도대로 잘 작동한다.

     

    그런데 자세히 보면 backBtn.addEventListener("click",function(){  this.backToDetail(id); }); 는 registerEvents() 메소드 내부에 있다. 즉 registerEvents() 내부에서 실행될 뿐 이 메소드 자체에 대한 호출자가 명확하지 않고 그게 이 함수에서 this가 undefinded로 확인되는 이유다. 그럼 어떻게 해야할까?

     

    복잡한 원인에 비해 해결책은 간단하다. this는 실행 문맥에 따라 결정되니 상위 메소드(?) registerEvents()의 실행 문맥을  backBtn.addEventListener("click",function(){  this.backToDetail(id); }); 에 bind해주면된다. 설명은 되려 복잡하니 아래 코드를 보자.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    promotionObj.prototype = {
            
            // 등록 이벤트
            registerEvents : function(id){
                // 뒤로 가기 버튼
                var backBtn = document.querySelector(".btn_back");
                
                backBtn.addEventListener("click",function(){
                    this.backToDetail(id);
                }.bind(this));
            }
     
    }
     

     

    불필요한 부분을 지운 것을 제외하고 위 코드와 달라진 건 .bind(this)가 추가된 것 밖에 없다.

    이것만 추가하면 this가 promotionObj 객체를 가르켜 코드가 의도대로 잘 작동한다.

     

    사실 이게 유일한 해결책은 아니다.  ES6의 arrow 함수를 사용하면 bind(this)를 사용하지 않고도 this를 잘 활용할 수 있다고 한다. 근데 이 부분은 잘 모르니 추후 다시 공부해서 포스팅 하는 걸로 하고 this와 bind를 이해하는데 큰 도움을 준 블로그와 edwith 강좌 해당편의 링크를 남기며 포스팅을 마친다

     

    참고 

     

     

    https://blueshw.github.io/2018/03/12/this/

     

    blueshw.github.io

     

    [LECTURE] 3) bind메소드로 this제어하기 : edwith

    들어가기 전에 this 키워드는 this를 사용하고 있는 함수가 어떻게 불리는가에 따라서 달라지는 경우가 있습니다. 이때 그 함수의 context가 참고하는 객체를 원하는 것으로 ... - moons

    www.edwith.org

     

    반응형

    댓글

Designed by Tistory.