JavaScript(JS) - this

조성주·2023년 2월 24일
1

JavaScript

목록 보기
9/21
post-thumbnail

✅ this란?

  • this는 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수(self-reference variable)이다.

    인스턴스는 클래스의 속성과 메서드를 담고 있는 객체이다. 클래스로 만든 객체가 인스턴스라고 생각하면 쉽다.

  • this는 메서드에서 객체 내부의 속성(property) 값을 접근할 수 있는 지시자이다.

  • this의 값은 호출된 함수에 따라 값이 바뀐다.

  • this는 자기 자신이 속해있는 객체를 뜻한다.!

  • 최상위 코드에서는 전역 객체를 받고, 함수 내부에서는 함수를 호출한 객체가 된다.

아래의 예제들을 통해 알아보자

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

car.getName()

위의 코드의 결과는 car getName KIA로 나온다. KIA로 나오는 이유는 현재 위에 코드에서 this는 호출이 됐을때 자기 자신이 위치해있는, 속해있는 객채를 뜻한다. 따라서 this(=car)가 되는 것이고 this.name이라고 하면 car.name 즉, KIA를 출력하게 된다.

그럼 만약에 객체 안에 있는 함수를 변수로 만들어 호출하게 되면 어떻게 될까? 위에 예제를 이어서 진행해보겠다.

1. 예제를 통한 this 접근

예제 1)

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

const globalCar = car.getName;
globalCar();

이렇게 하게되면 당연히 KIA가 출력되겠다 싶었지만 실제로 결과를 확인하면 undefined가 출력이 된다. 그 이유는 저 getName이라는 함수를 호출을 한 것은 globalCar라는 변수에서 호출이 된 것이기 때문에 this는 global 변수가 위치한 곳을 뜻한다. 하지만 지금 globalCar가 위치한 곳을 최상위이기 때문에 undefined로 나오게 된다.

좀 더 쉽게 정리하면 car.getName()을 A.B 라고 했을 때 this는 A를 참조한다 라고도 할 수 있다. 그렇기 때문에 globalCar()라고 했을 때 누가 호출했는지가 없기 때문에 그냥 B와 똑같다. 그래서 undefined로 나온다.

다른 예제로 this를 더 알아보자.

예제 2)

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

const car2 = {
  name: "hyundai",
  getName: car.getName,
};

car2.getName();

새로운 객체 car2를 생성을 하였는데 이번에는 예제1과는 다르게 getName이라는 key에 car에서 만든 getName을 넣었다. 이렇게 했을 때 호출하게 되면 this가 car에 있기 때문에 당연히 KIA가 나오지 않을까 싶었지만 실제로 결과를 출력했을 때는 내가 생각한 결과와는 달랐다.

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

const car2 = {
  name: "hyundai",
  getName: car.getName,
};

car2.getName(); // output : hyundai

결과는 hyundai가 출력이 되었다. 그 이유는 this는 car객체에 getName Key에 value에 this가 있었지만 실제로 저 함수를 호출한 것은 car2을 호출을 하면서 출력이 된 것이기 때문에 this는 car2에 name인 hyundai가 되는 것이다. 실제로 this만 출력을 하게 되면

이렇게 car2의 객체가 출력이 되는 것을 확인할 수 있다.

다른 예제로 this를 더 알아보자.

예제 3)

button의 DOM을 가지고 와서 클릭이벤트가 발생했을 때 car.getName을 호출되도록 코드를 작성하였다. 이렇게 되면 this는 어디를 참조하고 있는지 확인해보자.

확인을 해보면 button ID를 가진 DOM을 출력하는 것을 확인할 수 있다. button이 클릭됐을 때 car.getName함수를 호출하는 것이기 때문에 this는 button의 DOM이 되는 것이다.

예제 4)

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

testCar.getName();

위에 코드는 getName이라는 key에 value로 함수를 넣었는데 그 함수안에 또 함수를 만들어서 그 함수가 호출이 됐을 때 this는 무엇이 되는지 확인하는 코드이다. 확인해보면 this는 무엇이라고 출력이 될까?
결과를 확인해보면

getname { name: 'benz', getName: [Function: getName] }
innerFunc 

이렇게 결과가 나온다. 그 이유는 innerFunc을 누가 호출했는지가 없기 때문에 innerFunc을 호출했을 때는 아무것도 출력이 되지 않는다. A.B로 A가 B를 호출해야하는데 지금은 B만 있고 호출할려는 대상이 없기 때문에 아무것도 출력이 되지 않는다.

이렇게 위에서 정의한 this는 자기 자신이 속해있는 객체를 뜻한다. 이 내용은 호출한 대상이 this가 된다는 얘기와 동일하다는 것을 알 수 있다.

2. bind 함수

  • this를 고정시켜주는 함수이다.

car2.getName을 car로 bind(고정)하게 되면 아래와 같은 결과가 나온다.

const bindGetname = car2.getName.bind(car);
bindGetname()

이렇게 bind 함수를 통해서 this값을 고정시켜줄 수 있는 걸 확인할 수 있다.

3. 화살표 함수에서의 this

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

testCar.getName();

위에 this 예제 4번에서 사용한 코드인데 여기서 첫번째 this와 innerFunc에 this를 같게 할려면 어떻게 해야할까?
화살표 함수를 사용하면 된다.

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

testCar.getName();

이렇게 하면 화살표 함수는 상위 this를 계승받는다는 특징을 가지고 위에 this와 아래의 this를 같게 할 수 있다. 이 예제로 화살표 함수는 상위 this를 계승받는다는 것을 확인할 수 있다.

4. this의 다른 예제

예제 5)

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

ageTest.getAgeList();

이 경우에는 배열을 순회하면서 배열의 요소(element)들이 잘 출력이 된다. 하지만

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

ageTest.getAgeList();

이 경우에는 이 3번 출력이 될 줄 알았지만 실제로는 undefinded가 3번 출력된다. Map함수안에 파라미터로 콜백함수를 넣어주면 콜백함수는 map 함수 내부에서 일반함수로 호출되기 때문에 콜백함수안의 this는 전역객체를 참조하게 된다.

이게 무슨 얘기냐면 위에 예제 4번에서

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

testCar.getName();

이 코드에서 innerFunc()을 실행했을 때 결과가 아무것도 나오지 않은 이유는 innerFunc를 호출하는 대상이 없기 때문에 아무것도 결과가 나오지 않았다. map함수에서도 똑같이 콜백함수로 넣었지만 저 콜백함수는 일반함수이기 때문에 똑같이 결과가 나오지 않는 것이다. map으로 순회하면서 함수를 실행하는 것이기 때문에 아무것도 출력이 되지 않는다. A.B일 때 A가 this인데 A가 없이 B만 실행하기 때문에 아무것도 출력이 안된다.

따라서 넣어줄 때 콜백함수에 this 바인딩을 해줘서 this 정보를 같이 넘겨줘야 한다.
아니면 안에 콜백함수를 화살표 함수로 바꾸어서 상위 this를 계승받으면 unit 출력을 할 수 있다.

간단하게 정리하자면
1) this는 자기자신(this)가 속해 있는 객체를 가진다.
2) 객체.key(함수) -> A.B라고 했을 때 this는 A 객체를 가진다.
3) 만약, B로만 실행되면 전역 객체를 가진다.
4) 화살표 함수는 상위 this를 계승 받는다.

참고사이트 : https://www.youtube.com/watch?v=tDZROpAdJ9w

profile
프론트엔드 개발자가 되기 위한 기록

1개의 댓글

comment-user-thumbnail
2023년 2월 27일

제로베이스 프론트엔드 스쿨 입니다 !
과정 시작한지 2달이 다 되어가는데요.
공부하시면서 블로그 작성까지 하는 것이 쉽지
않으실텐데 정말 대단하신 것 같아요 !
취업 준비하실 때 많은 도움이 되실테니
힘드시더라도 끝까지
꾸준히 작성하시면 좋을 것 같습니다.
오늘도 화이팅 하세요:)

답글 달기