Javascript & React

[Javascript] this (일반 함수에서의 this, 화살표 함수에서의 this)

Hoo_Dev 2022. 12. 23. 10:35

오늘은 항상 애매하게 알고있던 Javascript의 this에 대해 정확히 짚고 넘어가보려고 한다.

참고 - [코딩알려주는누나]개발자 면접 단골질문 자바스크립트 this

this란?

  • this는 함수가 호출될 때 결정이 된다.

car라는 함수에서 this를 찍고 호출하여 값을 출력해보자.

const car = {
    name: 'KIA',
    getName: function () {
        console.log("car get Name", this)
    }
}

car.getName()

// 출력 결과
// car get Name { name: 'KIA', getName: [Function: getName] }
  • car라는 객체가 getName 함수를 호출했기 때문에 car 객체가 this로 나타남

 

이번엔 car 함수를 담은 새로운 함수인 globalCar를 생성하여 새로 호출해보자

const car = {
    name: 'KIA',
    getName: function () {
        console.log("car get Name", this)
    }
}

// car.getName()

const globalCar = car.getName
globalCar()

// 출력 결과
//   영상에선 브라우저에서 console을 확인하기 때문에 window 객체가 나오지만
//   필자는 node환경을 사용하기 때문에 node의 global객체가 나오는 점 참고
//			<ref *1> Object [global] {
//  global: [Circular *1],
//  queueMicrotask: [Function: queueMicrotask],

이 상황에선 부르는 객체없이 함수를 담은 값 자체를 글로벌에서 호출했기 때문에 this는 글로벌 환경 그 자체가 됨.

 

2번째 예제를 통해 확실히 알아보자

const car = {
    name: 'KIA',
    getName: function () {
        console.log("car get Name", this)
    }
}

  const car2 = {
    name: 'HYUNDAI',
    getName: car.getName
  }

  car2.getName()
// 출력 결과

// car get Name { name: 'HYUNDAI', getName: [Function: getName] }

이를 통해 알 수 있는 점은 this를 부르는 객체에 따라 바뀐다는 것을 알 수 있다.

만약 html에 버튼을 생성해서 버튼을 누를 때 this가 포함된 함수를 호출한다면?

btn.addEventListener('click', car.getName)

// 출력 결과
// car get Name  <button  id="button">this</button>

버튼 태그 그 자체가 나와버리게 됨.

그렇다면 this를 내가 원하는 값으로 지정해주고 싶을 땐? → .bind(해당객체)

const car = {
    name: 'KIA',
    getName: function () {
        console.log("car get Name", this)
    }
}

const globalCar = car.getName

  const car2 = {
    name: 'HYUNDAI',
    getName: car.getName
  }

const bindGetName = car2.getName.bind(car)
bindGetName()

// 출력 결과
// { name: 'KIA', getName: [Function: getName] } 

버튼 또한 위와 같은 방식으로 바인딩을 해준다면 원하는 객체를 가져올 수 있다.

const btn = document.getElementById('button')

  btn.addEventListener("click", car.getName.bind(car))

this 연습 예제

const testCar = {
    name: 'benz',
    getName : function () {
        console.log("getName", this.name)
        const innerFunc = function () {
            console.log("innerFunc", this.name)
        }
        innerFunc();
    }
}

testCar.getName()

// 출력 결과
// getName benz
// innerFunc undefined

왜 이런 결과가 나왔는지 다시 알아보자

const testCar = {
    name: 'benz',
    getName : function () {
        console.log("getName", this)
        const innerFunc = function () {
            console.log("innerFunc", this)
        }
        innerFunc();
    }
}

testCar.getName()

// 출력 결과
// getName { name: 'benz', getName: [Function: getName] }
// innerFunc <ref *1> Object [global] { ...

this로만 찍어서 확인해보면

innerFunc()같은 경우에는 호출자가 없기 때문에 글로벌이 호출하게 되고,

testCar.getName()은 testCar 객체가 호출했기 때문에 정상적인 name이 나왔던 것이다.

만약 innerFunc의 this도 testCar의 this와 같게 하고 싶다면?

  • .bind 사용
  • 화살표 함수 사용

화살표 함수를 사용해서 같게 해보자

  • 일반함수에서의 this와 화살표 함수에서의 this가 다르다.
  • 화살표 함수에서의 this는 함수가 속해있는 곳의 상위 this를 계승 받는다.
const testCar = {
    name: 'benz',
    getName : function () {
        console.log("getName", this)
        const innerFunc = () => {
            console.log("innerFunc", this)
        }
        innerFunc();
    }
}

testCar.getName()

// 출력 결과
// getName { name: 'benz', getName: [Function: getName] }
// innerFunc { name: 'benz', getName: [Function: getName] }

this 연습 예제 2

리스트들 뒤에 n’살’ 이라고 붙이고 싶은데 function을 쓰면 상위 객체의 unit을 계승받지 못하므로 NaN이 출력 되게 된다.

const ageTest = {
    unit:'살',
    ageList:[10, 20, 30],
    getAgeList:function () {
        const result = this.ageList.map(function(age){
            return age+this.unit;
        })
        console.log(result);
    }
}

ageTest.getAgeList()

// 출력 결과
// [ NaN, NaN, NaN ]

해결 방법은 화살표 함수를 사용하는 것 (*화살표 함수는 바인딩을 제공하지 않는다.)

const ageTest = {
    unit:'살',
    ageList:[10, 20, 30],
    getAgeList:function () {
        const result = this.ageList.map((age)=>{
            return age+this.unit;
        })
        console.log(result);
    }
}

ageTest.getAgeList()

// 출력 결과
// [ '10살', '20살', '30살' ]