일반함수의 this와 화살표함수에서 this는 다르게 정의된다. 

어떻게 다른지 알아보자.

 

일반함수호출 위치에 따라 this 정의!

화살표함수는 자신이 선언된 함수 범위에서 this 정의!

 

예제1)

const leo = {
  name: 'leo',
  normal: function () {
    console.log(this.name)
  },
  arrow: () => {
    console.log(this.name)
  }
}

leo.normal() //leo
leo.arrow() //undefined

leo라는 변수안에 객체테이터가 할당되어 있다.

여기서 일반함수로 정의된 부분은 호출 위치에서 정의되는데

normal메소드에서 일반함수로 선언했을 때

여기서 사용한 this는 어떤 걸 지칭하는지 알 수가 없다.

but 기본적으로 normal이란 메소드는

leo라는 객체데이터 내부에서 실행이 된다.

leo.normal() 이부분에서 호출이되고,

normal에 딸려있는 객체데이터는 leo이기 때문에

leo=this 가 되어 leo가 잘 출력되게 된다.

 

그러나, 화살표함수는 자신이 선언된 함수 범위가 존재하고

지금 코드에서는 외부에 함수가 보이지 않기 때문에

화살표함수 같은 경우엔, this가 사용 될 때

코딩환경에 따라서 다양한 의미로 this가 지칭될 수 있다. 

결국 화살표함수의 내부에서의 this는 현재 코드에서는

무엇인지 정확히 알 수 없고, 무엇인지 알 수 없는 상태에서

name 속성을 찾으려고 하니 정의되어 있지 않다는 undefined가 출력된다.

즉, arrow라는 메소드는 호출 위치랑은 전혀 상관없이 선언될 때

this가 무엇인지 충분히 알 수 있다.

왜냐하면 화살표함수는 자신이 선언된 함수 범위(어디인지 모르겠지만)

안에서 this가 정의되기 때문!

 

다시 한 번 코드를 살펴보며 알아보자.

예제2)

function User(name) {
  this.name = name
}
User.prototype.normal = function () {
  console.log(this.name)
}
User.prototype.arrow = () => {
  console.log(this.name)
}

const leo = new User('leo!!')

leo.normal()
leo.arrow()

위의 코드는 생성자 함수이다.

user라는 이름의 생성자 함수를 만드는데

밖에서 들어온 인수를 매개변수 name으로 받아,

this.name부분에 할당하고 있다.

그렇게 만든 user라는 함수부분에

프로토타입을 이용하여 normal 메소드를 생성할건데

normal은 일반함수를 사용해서 할당하고 있고, 

다음에는 arrow라는 화살표함수를 사용하여 할당하고 있다.

 

일반함수로 만들어진 부분은 this가 호출 위치에서 정의가 되니까
normal 메소드가 실행이되는 호출 위치에 연결되어 있는...

그 객체 (leo) 인스턴스에 연결이 되면서 leo는

곧 this라는 키워드가 되는 것이고, leo의 name부분에 밖에서 들어온
'leo!!'라는 문자데이터가 매개변수로 받아져서 leo!!가 출력된다. 

 

하지만 화살표함수로 만들어진 부분은 자신이 선언된 위치의

함수 범위에서 this가 정의되는 것인데.

위 코드의 범위에서는 함수가 보이지 않는다.

그래서 undefined가 출력되게 된다. 

 

새로운 예제를 보며 한 번 더 this를 이해해보자

예제3)

const timer = {
  name: '시계입니다!!',
  timeout: function () {
    setTimeout(function () {
      console.log(this.name)
    }, 2000)
  }
}
timer.timeout()

timer라는 변수를 만들었고, 그 안에는 객체데이터가 할당되어있다.

timeout이라는 매소드는 function키워드를 사용하여

일반함수로 실행하고있다.

그 내부에는 settimeout이라는 함수가 들어있고

타이머 함수는 인수를 두개 받을 수 있는데,

하나는 함수(콜백), 하나는 시간(2000ms)을 받을 수 있다. 

함수의 인수는 앞에서 '콜백'이라고 부른다고 정의하였고, 

위 코드를 출력하면 undefined가 출력된다.

'시계입니다!' 덱스트가 출력되길 원했는데......?

 

그럼 여기서 사용된 this는 어떻게 이해하면 좋을까?

this가 사용된 부분은 일반함수로 만들어져있고,

일반함수호출 위치에서 this가 정의되니까 

셋타임아웃이라는 내부로직으로 콜백이 들어가서

어디선가 실행이 되는것이다. 

만약에 this.name을 timer 객체데이터의 name부분('시계입니다!')이

지칭되서 출력되길 원했다면 일반함수로 정의했으면 안된다.

왜냐? 일반함수는 셋타임아웃의 로직 어딘가에서 실행이되기때문에

 

그래서....

const timer = {
  name: '시계입니다!!',
  timeout: function () {
    setTimeout(() => {
      console.log(this.name)
    }, 2000)
  }
}
timer.timeout()

코드를 화살표함수를 사용해서 바꿔주면 의도했던대로

'시계입니다!!'라는 데이터가 잘 출력되게 된다.

(console.log(this.name)이란 부분을 timeout이라는 객체데이터가 감싸고 있기때문에!)

그래서 보통 타이머함수를 사용할 땐

콜백으로 화살표함수를 쓰는것을 권장한다. 

 

결론: 일반함수에서는 호출 위치에 따라 this 정의!
화살표함수는 자신이 선언된 함수 범위에서 this 정의!
내가 원하는 의도에 따라 잘 구분하여 사용해야 한다.
그리고 화살표함수와 일반함수의 가장 큰 차이점은 내부에서 사용하는 this키워드의 차이점이라는 것. 
(this가 없을경우엔 일반함수를쓰던 화살표함수를 쓰던 이상무)

'개발이야기 > JS' 카테고리의 다른 글

[JS] 문자 (String) (.slice, .replace, .match, .trim)  (2) 2022.02.25
[JS] 반복문과 배열 조합  (0) 2022.02.22
[JS] JS 클래스 (new, this, prototype)  (0) 2022.02.15
[JS] 콜백  (0) 2022.02.15
[JS] 타이머 함수  (0) 2022.02.15
복사했습니다!