javascript 특강 - this 의 이해

JungSik Heo·2023년 1월 6일

Vue 3.0 강의

목록 보기
18/29

this는 자바나 C 언어의 this 와 다름에서 개발자들이 많이 헤깔려 한다.

자바스크립트로 개발을 하다보면 this를 다룰일이 많이 있다.

자바스크립트에서 this는 현재 코드가 실행되는 상황에 따라 할당되는 값이 달라지는데, 언제 어떤 값이 this에

할당되는지 제대로 이해하지 않고 대충 얼버무리고 넘어간다면 어디가서 JS좀 한다 같은 소리는 고이 접어두자.

"this 바인딩 이 정도면 다 이해한듯?" 그 당시엔 이렇게 생각이 들었어도, 시간이 흐르고 this로 복잡한 작업을 하다보면 금세 또 헷갈리고 인터넷을 찾게된다. 그래서 이번엔 this에 대해 최대한 정리해 보려한다.

함수와 this

일반적인 함수를 호출했을때, 함수내에 this는 무엇을 담고 있을까.?

function fn(){
    console.log(this); // (A)   -> window ? undefined ?
}
fn();

함수를 호출하면 (A)에서 전역객체 window가 출력될 것이고, 엄격모드라면 undefined 가 출력될 것이다.

이것이 this 바인딩의 가장 기본적인 상황이다.

그런데 자바스크립트에서 모든 함수는 생성자 함수이기도 하다. 그래서 함수를 호출할 때 앞에 new 를 명시하면

해당함수는 객체를 반환하게 되고 생성자 함수 내부에서 사용된 this는 반환된 객체를 가리키게 된다.

생성자 함수로 객체를 생성하는 예시를 보자.

function Person(){
    this.name = 'sunny';
    this.showThis = function(){
        console.log(this);
    }
}

let me = new Person();
me.showThis(); // (A)

(A)에서 me.showThis 를 실행하여 this를 출력해보면 this는 생성된 객체 자신인걸 확인 할 수 있다.

함수가 new를 만났을때 객체가 생성되는 과정을 좀더 자세히 보면 아래와 같다.

function Person(){
    // this = {} --> 빈 객체가 할당된 this가 암묵적으로 만들어진다.
    this.name = 'sunny';
    this.showThis = function(){
        console.log(this);
    }
    // return this; --> 암묵적으로 this를 리턴한다.
}

메서드와 this

아래의 연산결과를 예상해 보자

var myName = 'kwang'; // 함수 바깥에서 선언된 var 변수는 전역객체의 프로퍼티가 됨.

function fn(){
    console.log(this);
    console.log(this.myName);
}

let obj = {
    myName: 'sunny',
    func: fn, // (A)
}

fn(); // (B)
obj.func(); // (C)

만약 객체 A, B가 있다고 할때, A의 메서드를 B의 프로퍼티로 할당해주면 어떻게 될까?

B에서 이 메서드를 실행하면 this 는 A, B 중 어떤 객체를 가리키게 될까?

let A = {
    myName: 'A',
    func: function(){
        console.log(this);
        console.log(this.myName);
    }, 
}

let B = {
    myName: 'B',
    func: A.func,  // (A)
}

A.func();
B.func();

실행결과를 보면 this는 호출된 함수가 속한 객체를 가리키고 있다.

(A) 에서 B.fucn = A.func 를 해주고 있는데 왠지 B.func 를 실행하면 this 는 A 를 가리킬것 같지만 그렇지 않았다.

메서드는 자신을 호출한 객체를 this로 할당한다. 그래서 같은 함수를 공유한다 하더라도 this의 값은

호출되는 시점에 어떤 객체에서 호출했냐에 따라 그 메서드의 this 값은 달라질 수 있다.

let obj = {
    myName: 'sunny',
    func: function(){
    	console.log('name is ' + this.myName);
    }
}

let say = obj.func; // (A)
say();

setTimeout(obj.func, 1000); // (B)

(85는 setTimeout이 반환한 타이머값 이므로 무시!)

메서드가 단독으로 호출된다는 의미는 위의 (A), (B) 와 같은 상황들을 말한다.

메서드가 object.method() 와 같은 형태로 호출되지 않고 어떤 변수에 담기거나, 콜백함수로써 다른 함수에 전달되어

호출될때, 메서드는 일반함수를 호출할 때와 같은 규칙을 따르게되서 this는 전역객체를 가리키게 된다.

이벤트 콜백과 this

html 요소에 이벤트를 핸들러를 할당하는 방식은 세 가지가 있다.
1. html 속성값으로 할당
2. on 프로퍼티로 할당
3. addEventListener 로 할당

위 세 가지 방식중 뭘 사용하든 이벤트 콜백에서 this는 이벤트가 발생한 요소를 가리키게된다.

즉, this === event.currentTarget 이 된다.
그럼 진짜 그렇게 되는지 확인해보자.

<button onclick="clickA(event)">A</button>
<button id="btnB">B</button>
<button id="btnC">C</button>

<script>
    function clickA(e){
    	console.log(this);
        console.log(e.currentTarget === this);
    }
    
    btnB.onclick = function(e){
    	console.log(this);
        console.log(e.currentTarget === this);
    }
    
    btnC.addEventListener("click", function(e){
        console.log(this);
        console.log(e.currentTarget === this);
    });
</script>

on 방식과 addEventListener 방식의 콜백함수에서 this는 이벤트가 발생한 요소를 가리키고 있는

모습을 확인할 수 있다.

그런데 html 속성으로 할당해준 핸들러의 this는 왜 전역객체를 가리키는걸까..?

그 이유는 간단하다.

html 속성으로 할당해준 이벤트는 해당 이벤트가 발생했을때 속성값을 본문으로 삼는 새로운 함수를

만들어 실행하기 때문이다.

즉, A 이 버튼은 클릭 이벤트가 발생되면

아래 코드와 같이 속성값을 실행하게 된다. 그래서 clickA 는 일반함수가 호출될때와 같은 규칙을 따라 this에

전역객체 할당되어 위 결과에서 window 객체가 출력된 것이다.

  (function(){
    clickA(event);
})()

우리가 html 속성으로 이벤트 함수를 할당할때 가 아니라 이렇게 괄호를 붙여서

바로 호출하는 형태로 써주는것도 바로 이 이유때문이다.

화살표 함수와 this

마지막으로 화살표 함수에서 this는 어떤값을 가리킬지 알아보자.

화살표 함수는 위의 예시들과는 달리 this를 바인딩하지 않는다.

지금까지 봤던 this 바인딩은 함수가 호출되는 시점에 발생하는 동적 바인딩 이지만, 화살표 함수는 정적 바인딩이다.

정적 바인딩이란, 함수가 선언된 순간 코드상으로 바로 바깥쪽에 있는 스코프의 this를 사용한다는 뜻이다.

https://kwangsunny.tistory.com/40

profile
쿵스보이(얼짱뮤지션)

0개의 댓글