deVSner

화살표 함수 시에 발생하는 this 문제 해결 과정 본문

Error collection/js 에러

화살표 함수 시에 발생하는 this 문제 해결 과정

RudeofSun 2020. 3. 26. 21:10

화살표 함수라는, 꽤나 그럴 싸 해 보이는 방법이 있습니다.

많은 분들은 익히 들어보시고 사용하고 계실겁니다.

 

저는 최근에 이 화살표 함수라는 것을 사용하게 되었는데요...

방법만 안 채로, 막 사용하다가 왜 에러가 나는지를 몰랐던 적이 한 두번이 아닙니다.

 

분명 되는 곳일텐데?

여긴 또 왜 안되는거지?

라고 생각하면서 코드를 몇 번 엎었던 적이 있습니다.

이게....화살표 함수 때문에....그렇다는 것을 오늘에서야 알게 되었습니다.

 

우선, 문제 코드부터 먼저 보시죠.

 

 

주석으로 울고 있는 부분이 오늘의 포인트입니다.

사진에는 하나지만, 실제로 5군데에서 제가 화살표 함수를 사용하여 낭패를 봤습니다.

 

결론을 말씀드리면,

화살표 함수로는

1. 메소드를 만들면 안되며,

2. prototype을 만들면 안되며,

3. 생성자 함수를 만들면 안되며,

4. addEventListener 함수의 콜백 함수로써 사용하면 안된다는 것입니다.

 

이번 문제 해결 과정을 통해서 배운 것은,

'좀 제대로 알고 쓰자'입니다. 이게 엄청 간단하게 들릴 지는 모르겠지만,

저는 비전공자 출신에 코딩부트캠프에서 거의 속성으로 많은 양의 지식을 머리 속에 넣고 있습니다.

또 그걸 통해서 바로 실전 코드를 작성하고 평가 받고 있죠.

그렇기 때문에, 이론적인 부분을 화두로 받게 되면, 저는 그것에 대해 깊이 공부해야 할 의무가 있습니다.

다만, 이번 같은 경우엔 화살표 함수가 개념적인 부분이라고 생각하지 못했기 때문에, 일어난...불..상사.....였습니다.. ㅠㅠ

 

자,

function으로 만든 함수나,

화살표로 만든 함수나 똑같은 함수인데,

 

무슨 차이가 있는지는 일반함수와 화살표 함수, 그리고 this에 대한 이론적인 부분을 설명해가며 알아보겠습니다.

이번 Dev log를 통해 정말 많은 걸 배웠다는 느낌이 듭니다.

 

1. 일반 함수의 this와 화살표 함수의 this

자바스크립트는 함수 호출 방식에 의해 this에 바인딩할 특정 객체가 동적으로 결정이 됩니다. 

즉, 함수 선언 시에, this에 바이딩할 객체가 정적으로 결정되는 것이 아니라 함수를 호출할 때 함수가 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정된다는 것입니다.

 

function Burger(brand) {
  this.brand = brand;
}

Burger.prototype.name = function(nameArr) {
  // (a)
  return nameArr.map(function(el) {
    return this.brand + ' ' + el;  //(b)
  });
};

var kingburger = new Burger('king');
console.log(kingburger.name(['paty', 'sang-chu']);

a지점에서 this는 생성자 함수 Burger가 생성한 객체를 가리킵니다. 인스턴스인 kingburger를 가리키죠.

 

b지점에서는 인스턴스가 아니라 window를 가리킵니다.

왜냐하면, 생성자 함수와 객체의 메소드를 제외한 모든 함수(내부 함수, 콜백함수 포함) 내부의 this는 전역 객체를 가리키지 떄문입니다.

 

그렇다면, 콜백 함수 내부에서 this가 메소드를 호출한 객체(생성자 함수의 인스턴스)를 가리키게 하려면

어떤 방법이 있을까요?

 

3가지가 있습니다.

1. that 변수에 this를 할당하는 것

2. map(func, this)를 사용하는 것 (map이 일반적인 사용은 아니기 때문에 설명은 생략)

3. Function.prototype.bind()로 this를 바인딩하는 것

 

1.

function Burger(brand) {
  this.brand = brand;
}

Burger.prototype.name = function(nameArr) {
  // (a)
  var that = this;
  return nameArr.map(function(el) {
    return that.brand + ' ' + el;  //(b)
  });
};

var kingburger = new Burger('king');
console.log(kingburger.name(['paty', 'sang-chu']);

 

2.

function Burger(brand) {
  this.brand = brand;
}

Burger.prototype.name = function(nameArr) {
  // (a)
  return nameArr.map(function(el) {
    return this.brand + ' ' + el;  //(b)
  }.bind(this));  //this : Burger생성자 함수의 인스턴스
};

var kingburger = new Burger('king');
console.log(kingburger.name(['paty', 'sang-chu']);

 

여기까지 일반함수의 this가 가리키는 대상과 원하는 this가 되게 만드는 방법에 대해 살펴보았습니다.

 

지금부터 오늘 문제를 해결하는데 큰 도움이 되었던 이론을 설명합니다.

 

2. 화살표 함수의 this

화살표 함수는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정됩니다. 즉, this는 언제나 상위 스코프의 this를 가리킨다는 뜻입니다. 이를 Lexical this라고 합니다.

 

화살표 함수는 call, apply, bind 메소드를 사용하여 this를 변경할 수 없습니다.

window.x = 1;
const normal = function () { return this.x; };
const arrow = () => this.x;

console.log(normal.call({ x: 10 })); // 10
console.log(arrow.call({ x: 10 }));  // 1

글 시작부분에서 화살표 함수로는 메소드와 프로토타입, 생성자 함수, addEventListener의 콜백함수로 사용하면 안된다고 했습니다.

 

- 메소드와 프로토타입으로 화살표 함수를 사용하였고, 그 안에 this가 있다면, 그 this는 메소드를 호출한 객체를 가리키는 것이 아니라, 상위 컨택스트인 전역 객체 window를 가리킵니다.

 

- 생성자 함수는 프로토타입 프로퍼티를 가지고 프로토타입 프로퍼티가 가리키는 프로토타입 객체의 constructor를 사용합니다. 하지만 화살표 함수는 프로토타입 프로퍼티를 가지고 있지 않습니다.

 

 

 

Dev log를 통해 새로운 이론을 많이 설명했습니다. 마치 오늘의 데브로그는 러닝 로그에 들어가야 할 것만 같은....ㅋㅋㅋ

 

 

'Error collection > js 에러' 카테고리의 다른 글

Uncaught (in promise) TypeError: Failed to fetch  (0) 2020.05.05
cors 에러  (0) 2020.05.05