자바스크립트 this 정리(deprecated)

Kyung yup Lee·2021년 1월 5일
1

자바스크립트

목록 보기
1/12

es6에서 변화된 내용을 공부하고 있는데 arrow function 을 공부하다가 계속 미루고 미루던 this의 개념에 부딪혀 이건 정리 안하면 넘어가기 힘들겠다고 생각이 들어

드디어 정리를 하려고 한다.

자바스크립트에서 this 가 논란의 중심이 되는 이유는 한 가지 개념만 가지는 게 아니라 여러 상황에서 다르게 기능하기 때문이다.

java를 공부했던 사람은 this가 자기 자신인 객체를 가리키는 개념이라고만 알고 있다. 그 외 역할은 따로 없다. 그렇기 때문에 자바에 익숙해진 사람이 자바스크립트의 this 를 보면 예상 밖의 기능을 하는 것에 당황하는 것이다.

이 글에선 다양한 this 의 상황에 따른 기능을 정리하려고 한다.

  • 함수 실행 : alert('Hello world!')
  • 메소드(함수 내부의) 실행 : console.log('Hello world!')
  • 생성자 실행 : new RegExp('\d')
  • 간접(indirection) 실행 : alert.call(undefined, 'Hello world!');

출처: https://kim-solshar.tistory.com/42 [김솔샤르의 인사이트]

함수 실행

function myFunc() {
    console.log(this);
}
myFunc();

해당 함수를 실행하면 콘솔 창에는 window 전역 객체가 찍혀나온다.

함수 부분에서 this 를 사용하면 this는 전역객체를 가르킨다.

메소드 실행

var obj = {
  count: 1,
  helloFunc: function () {
    console.log(this.count);
  },
};
obj.helloFunc();

위 예제 처럼 함수 실행이 아닌, 객체 내부의 메소드 실행을 할 경우 자바에서의 사용과 같이 this는 해당 객체를 가리키게 된다.

생성자 함수 실행

function Country(name, traveled) {  
    this.name = name ? name : 'United Kingdom';
    this.traveled = Boolean(traveled); 
    
 }
 Country.prototype.travel = function() {  
   this.traveled = true;
   console.log(this)
 };
 var france = new Country('France', false);  
 var unitedKingdom = new Country;
  
 france.travel();

자바스크립트의 모든 함수는 생성자 함수가 될 수 있다. 생성자는 객체를 만들어내는 initiator 이다. 때문에 이 생성자 함수와 일반 함수를 구분짓는 것은 new 키워드를 통해 새로운 객체를 만들어내었는가 아닌가로 구분지을 수 있다.

새로운 객체를 만들게 된다면 해당 console.log(this) 는 Country 객체를 가르키게 된다.

결과는

Country { name: 'France', traveled: false }
Country { name: 'United Kingdom', traveled: false }

이렇게 나온다.

만약 new 키워드를 통해 객체를 만들어낸 것이 아닌, 위 예시에서

Country("hello" , true); 로 함수를 실행을 시켜버리면 결과는 일반 함수의 실행과 마찬가지로 window 전역 객체를 가리키게 된다. 때문에 이 생성자 함수와 일반 함수는 형태만으로는 구분이 불가능하지만, new 키워드로 객체화를 시키는지 아닌지를 잘 구분해야 한다. 또한 생성자 함수는 앞 글자를 대문자로 사용하는 것으로도 구분한다.

간접실행

자바스크립트에는 자바스크립트 함수가 가지고 있는 공통적인 메소드와 속성이 있다. 함수에서 이 메소드를 호출해 함수를 실행하는 것이 간접실행이다.

function increment(number) {  
  return ++number;  
  console.log(this)
}
increment.call("hi", 10);    // => 11  
increment.apply("hello", [10]); // => 11  

위의 increment 함수에서 call() 과 apply() 메소드를 통해 간접적으로 함수를 실행했다.

이 때 함수안에 this가 있으면 이 this 는 메소드의 첫번째 인자를 가리킨다.

즉 위의 예에서는 [String : "hi"], [String : "hello"] 가 출력된다.

후...... this를 공부하고 나니
es6 가 발표 되기 이전에 왜 사람들이 자바스크립트를 언어로 취급조차 안했는지 알 수 있었다.

function objFunction() {
  console.log('Inside `objFunction`:', this.foo); // 13
  return {
    foo: 25,
    bar: function() {
      console.log('Inside `bar`:', this.foo); // 25
    },
  };
}
 
objFunction.call({foo: 13}).bar(); // objFunction의 `this`를 오버라이딩한다

위 예시를 보자.

내가 공부하면서 아주 기겁을 한 예시다. 한 함수에서 같은 this.foo를 출력하는데 결과 값이 다르다.

위의 콘솔에서의 this.foo 는 objFunction의 간접실행이기 때문에 this 가 call의 인자로 받아진 {foo:13} 을 가르키게 되고, 아래 콘솔의 this.foo 는 메소드의 this 이기 때문에 return 하는 객체의 foo를 가리키게 된다. 그래서 출력 결과가 13과 25로 다르다.

이 말은 즉슨 코드를 아주 꼼꼼하게 문맥을 따라 읽어야 버그를 잡아낼 수 있다는 얘기이다. 더해서 버그도 엄청나게 많이 생길 수 있다.

다음엔 arrow function을 하면서 arrow function에서의 this는 어떻게 작동하는지, 전반적인 arrow function은 기존의 function과 어떤 것이 다른지를 정리해야 될 것 같다.

profile
성장하는 개발자

0개의 댓글