[JS] JS에서 this란?(1)

고정원·2021년 6월 19일
0

1Q/1Day

목록 보기
5/13
post-thumbnail

정재남,『코어자바스크립트』를 읽고 정리한 내용입니다. 이해가 부족한 부분은 책과 동일하게 작성하였습니다.

😎this를 왜 알아야하는지 궁금하다.. 더 많은 개발경험이 필요하드아.. : )_

  • 다른 대부분의 객체지향 언어에서 this
    → 클래스로 생성한 인스턴스 객체를 의미
  • 자바스크립트에서의 this
    → 어디에서든 사용가능, 상황에 따라 this가 바라보는 대상이 달라짐🥴

1. 상황에 따라 달라지는 this

자바스크립트에서 this는 기본적으로 실행 컨텍스트가 생성될 때 함께 결정된다.

  • 실행컨텍스트는 함수를 호출할 때 생성 = this는 함수를 호출 할 때 결정됨

함수를 어떤 방식으로 호출하느냐에 따라 값이 달라진다.

1.1 전역공간에서의 this

전역 공간에서 this는 전역 객체를 가리킨다.
전역 객체는 자바스크립트 런타임 환경에 따라 다른 이름과 정보를 갖는다.

  • 브라우저 환경 : 전역객체는 window
  • Node.js 환경 : global

JS의 모든 변수는 실은 특정 객체의 프로퍼티로서 동작
전역변수를 선언하면 JS엔진은 이를 전역객체의 프로퍼티로 할당

1.2 메서드로서 호출할 때 그 메서드 내부에서의 this

함수 vs .메서드
어떤 함수를 실행하는 방법 중 가장 일반적인 방법 두가지
1) 함수로서 호출 : 함수 그자체로 독립적인 기능 수행
2) 메서드로서 호출 : 자신을 호출한 대상 객체에 관한 동작을 수행
자바스크립트는 상황별로 this 키워드에 다른 값을 부여하게 함으로써 이를 구현했다.

함수로서 호출과 메서드로서 호출을 어떻게 구분할까?
함수 앞에 점(.)이 있는지 여부로 간단하게 구분가능!

메서드 내부에서의 this
this에는 호출한 주체에 대한 정보가 담긴다.어떤 함수를 메서드로서 호출하는 경우 호출 주체는 바로 함수명(프로퍼티) 앞의 객체이다. 점(.) 앞에 명시된 객체가 곧 this이다.

1.3 함수로서 호출할 때 그 함수 내부에서의 this

1)함수 내부에서의 this
함수를 함수로서 호출할 때는 this가 지정되지 않는다. this는 호출한 주체의 정보를 가리키는데, 자바스크립트에서는 함수를 함수로 호출하는 경우에는 호출주체가 없다(객체지향언어라면 호출주체는 객체가 된다). 이런 경우에는 함수의 this는 전역객체를 가리키는데, 이를 자바스크립트이 설계오류라고 한다.

2)메서드의 내부함수에서의 this
바로 앞에서 언급한 설계오류로 인해서 this가 무얼 가리키는지 혼란스러울때가 많다. 하지만 함수를 '함수로 호출할 때 this가 가리키는 것'과 '메서드로 호출할 때 this가 가리키는 것'은 다르다는 것을 알고 구분하면 된다.

let obj1 = {
  outer: function(){
    console.log(this); //obj1
    let innerFunc = function(){
      console.log(this); //window(전역객체) obj2.innerMethod
    }
    innerFunc();
    
    let obj2 = {
      innerMethod: innerFunc
    };
    obj2.innerMethod();
  }
};
obj1.outer();

3)메서드의 내부함수에서 this 우회하는 방법
그렇지만 이렇게 하는것이 헷갈리거나 전역객체를 바인딩하지 않고 호출 당시 주변환경의 this를 그대로 받게 하고 싶다면 변수를 활용 하면 된다.
변수명은 _this,that,self 등을 많이 쓰는데 뭐든 상관 없다. 변수는 상위 스코프의 this를 저장해서 내부함수에서 활용하려는 수단일 뿐이므로 의미만 통하면 된다.

var obj = {
  outer: function  () {
    console.log(this);    // this -> obj
    var innerFunc1 = function () { 
      console.log(this);  // this -> window
    }
    innerFunc1();

    var _this = this; // outer 환경의 this를 할당

    var innerFunc2 = function () {
      console.log(self);  // this -> obj
    }
    innerFunc2();
  }
};
obj.outer();

4)this를 바인딩하지 않는 함수(feat.화살표함수)
ES6에서는 함수 내부에서 this가 전역 객체를 바라보는 문제를 보완하고자, this를 바인딩하지 않는 화살표함수(Arrow Function)을 도입했다.화살표함수는 실행 컨텍스트를 생성할 때, this바인딩 과정 자체가 빠지게 되어 상위 스코프의 this를 그대로 활용 할 수 있다!
내부함수를 화살표 함수를 쓰면 this가 전역객체를 가리키지 않게 할 수 있다. 위에서 설명한 우회법이 불필요해진다.

1.4콜백함수 호출 시 그 함수 내부에서의 this

함수 A의 제어권을 다른 함수(또는메서드) B에게 넘겨주는 경우 함수A를 콜백 함수라 한다. 이때 함수A는 함수B의 내부 로직에 따라 실행되며, this 역시 함수 B 내부로직에서 정한 규칙에 따라 값이 결정된다.

콜백함수도 함수니까 기본적으로 this가 전역객체를 참조하지만, 제어권을 받은 함수에서 콜백 함수에 별도로 this가 될 대상을 지정한 경우에는 그 대상을 참조한다.

setTimeout(function () {
  console.log(this);
}, 300); // this를 가리키는 대상을 지정하지 않았으므로 this는 전역객체인 window객체를 가리키게 된다.   

[1,2,3,4,5].forEach(function (x) {
  console.log(this, x);
}); // this를 가리키는 대상을 지정하지 않았으므로 this는 전역객체인 window객체를 가리키게 된다

document.body.innerHTML += '<button id="a">클릭</button>';
document.body.querySelector('#a')
  .addEventListener('click', function(e) {
    console.log(this, e)
  });   // addEventListener 자신이 가리키는 this를 콜백함수가 가리키도록 한다	

🤓콜백함수에서의 this는 무조건이거~라고 정의할 수 없다.
콜백함수의 제어권을 가지는 함수(메서드)가 콜백 함수에서의 this를 무엇으로 할지를 결정하며, 특별히 정의하지 않은 경우에는 기본적인 함수와 마찬가지로 전역객체를 바라본다.

1.5 생성자 함수 내부에서의 this

생성자함수는? 어떤 공통된 성질을 지니는 객체들을 생성하는 데 사용하는 함수
JS는 함수에 생성자로서의 역을 함께 부여했다. new명령어와 함께 함수를 호출하면 해당 함수가 생성자로서 동작한다. 그리고 어떤 함수가 생성자 함수로서 호출된 경우 내부에서의 this는 곧 새로 만들 구체적인 인스턴스 자신이 된다.

구체적인 인스턴스가 만들어지는 과정은 다음과 같다. 생성자함수의 prototype을 참조하는 _ proto _ 라는 프로퍼티가 있는 인스턴스를 만들고 공통속성, 개성을 해당 인스턴스 즉 this에 부여하면 된다.
코드로 예를 들어보자.

var Cat = function (name, age) {
  this.bark = '야옹';
  this.name = name;
  this.age = age;
};

var choco = new Cat('초코', 7);
var nabi = new Cat('나비', 5);
console.log(choco, nabi);

Cat이란 변수에 할당된 함수 내부에서는 this의 프로퍼티에 인자러 입력된 값을 대입해준다. 이후 new 명령어와 함께 생성자함수 Cat를 호출하면 인자로 입력된 값들이 this가 가리키는 인스턴스들의 프로퍼티로 저장이 된다. 다시말해, var choco = new Cat('초코', 7)에서 this는 choco 인스턴스를 가리키고, 인자로 입력된 값들이 choco 인스턴스의 프로퍼티로 저장이 되는 것이다.

다음글에서 위의 규칙을 깨고 this에 별도의 대상을 바인딩하는 방법에 대해 알아봅시다.

[참고자료]
정재남, 『코어자바스크립트』, 위키북스(2019)
https://velog.io/@heo-mk/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%8A%A4%ED%84%B0%EB%94%94-%EC%BD%94%EC%96%B4%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-3%EC%9E%A5-this

profile
해결문제에 대해 즐겁게 대화 할 수 있는 프론트엔드 개발자

0개의 댓글