JS this에 대하여


Javascript에서 this란 무엇이고, 어떤 역할을 하는지, 상황에 따라 어떻게 this를 해석해야 하는지 알아봅니다.



0. this란?

this는 현재 실행 중인 코드가 속한 개체, 클래스 또는 다른 엔티티를 참조하기 위해 일부 컴퓨터 프로그래밍 언어에서 사용되는 키워드입니다.

this에 의해 참조되는 엔터티는 실행 컨텍스트(예를 들어 메소드가 호출되는 객체)에 따라 달라집니다. (by wiki)


위 설명에 의하면 실행 컨텍스트에 따라 this 값이 달라진다고 합니다.
우선 맨 처음 시작 점인 전역 컨텍스트에서 this를 알아볼까요?

브라우저에서 F12를 눌러 콘솔 창을 열어봅시다.
거기서 this를 호출하면 무엇이 나올까요?
window란 객체가 출력됩니다. (nodejs 콘솔 창에서는 global이 나옵니다.)

브라우저에서의 this 값
browser this

nodejs에서의 this 값
nodejs this

현재 브라우저에 열린 콘솔 창은 전역 실행 문맥입니다.
전역 실행 문맥(global execution context)에서 this는 전역 객체를 참조합니다.
즉, 브라우저의 전역객체는 window이고 nodejs의 전역객체는 global이란 거죠~


1. 메서드에서의 this

메서드 내부 코드에서 사용된 this는 해당 메서드를 호출한 객체로 바인딩됩니다.

예제 1

function getThis() {
  return this;
}


내부 함수에서 this를 호출하면 전역 객체인 window가 호출됩니다.
예제 1에서 getThis 함수는 전역에서 정의되었습니다.
전역에서 정의되었다는 것은 window 객체에 정의 되었다는 것입니다.
그러므로 getThis() 함수 호출은 window.getThis()와 동일한 호출입니다.
window 객체가 getThis를 호출했기 때문에 getThis 함수 내부에서 this는 window 객체를 가르키게 됩니다.



예제 2

var John = { 
  name: 'John', 
  getName : function () {
      return this.name;
  },
  getNameFunc : function () {
    return this.getName;
  }
};


예제 2에서 John.getName() 이라고 실행할 경우 getName 내부의 this는 어떻게 될까요?
getName을 호출하는 John 객체가 됩니다.
만약 전역인 window 객체에서 getName() 호출한다면 this는 어떻게 될까요?
getName 내부의 this는 window 객체가 됩니다.


예제 3 (문제가 발생하는 경우!)

var John = { 
  name: 'John', 
  getName : function () {
    addGender = function () {
      return this.name + ':남자'
    }
    return addGender();
  } 
};


John.getName()을 통해 ‘John:남자’라는 값을 기대했지만, ‘:남자’가 나오게 된다. addGender 함수 내부에서 this가 John이 아닌 Window를 의미하기 때문이다.

#해결방법 1 (this 저장)

var John = { 
  name: 'John', 
  getName : function () {
    var that = this;
    addGender = function () {
      return that.name + ':남자'
    }
    return addGender();
  } 
};


#해결방법 2 (bind 함수 사용)

var John = { 
  name: 'John', 
  getName : function () {
    addGender = function () {
      return this.name + ':남자'
    };
    addGender = addGender.bind(this);
    return addGender();
  } 
};


#해결방법 3 (call, apply 사용)

var John = { 
  name: 'John', 
  getName : function () {
    addGender = function () {
      return this.name + ':남자'
    };
    
    return addGender.call(this)
  } 
};
var John = { 
  name: 'John', 
  getName : function () {
    addGender = function () {
      return this.name + ':남자'
    };
    
    return addGender.apply(this)
  } 
};

var foo = {};

Person.apply(foo, [‘foo’, ‘30’, ‘man’]); console.dir(foo); Person.call(foo, ‘foo’, ‘40’, ‘man2’); console.dir(foo);

 - [부록 3. this 바인딩 활용 예제](#부록-3-this-바인딩-활용-예제)

<br/>

#### #해결방법 4 (화살표 함수 사용)
```js
var John = { 
  name: 'John', 
  getName : function () {
    addGender = () => {
      return this.name + ':남자'
    };
    
    return addGender();
  } 
};


var John = { 
  name: 'John', 
  getName : function () {
    addGender = () => {
      return this.name + ':남자'  // 이 함수 내부의 this는 null이다. 그래서 바깥쪽 this를 찾는다. 
    };
    
    console.log(this) // 여기에서 this는 John이다. 
    return addGender();
  } 
};
var John = { 
  name: 'John', 
  getName : () => {
    addGender = () => {
      return this.name + ':남자' // 이 함수 내부의 this는 null이다. 그래서 바깥쪽 this를 찾는다. 
    };
    
    console.log(this)  // 이 함수 내부의 this 또한 null이다. 그래서 바깥쪽 this를 찾는다. (window가 반환된다.)
    return addGender();
  } 
};



2. 생성자에서의 this

생성 순서

  1. 빈 객체 생성 및 this 바인딩
    • 빈 객체를 생성한 후 생성자 함수의 prototype 프로퍼티가 가리키는 객체를 자신의 프로토타입 객체로 설정한다.
  2. this를 통한 프로퍼티 생성
    • 함수 코드 내부에서 this를 사용해서, 앞에서 생성된 빈 객체에 동적으로 프로퍼티나 메서드를 생성할 수 있다.
  3. 생성된 객체 리턴
    • 특별하게 리턴문이 없을 경우, this로 바인딩된 새로 생성한 객체가 리턴된다.
    • 다른 객체를 반환하는 경우 생성자 함수를 호출했다고 하더라도 this가 아닌 해당 객체가 리턴된다.


예제

function Person(name) { 
  this.name = name; 
  this.getName = function(){
    return this.name;
  };
};

var John = new Person('john');
John.getName(); // 1. 'john' 출력
John.__proto__ === Person.prototype; // 2. true 출력
Person === Person.prototype.constructor; // 3. true 출력
Person.__proto__ === Function.prototype // 4. true 출력
  1. 생성자 함수로 John이 생성될 때, 빈 객체를 this에 바인딩 후 함수를 실행하고, 그 this를 John 변수에 넘기기 때문에 John.getName()이란 함수가 존재할 수 있게 되고, john이란 name이 정상적으로 출력된다.
  2. John의 부모역할을 하는 prototype은 생성자 함수 Person의 prototype이다.
  3. 생성자 함수 Person의 prototype은 constructor 변수를 통해 생성자 함수인 Person을 가르킨다. (생성자 함수인 Person은 prototype 변수로 생성자 함수의 prototype을 가르킨다.)
  4. 생성자 함수 Person의 부모역할을 하는 프로토타입은 Function의 프로토 타입이다.




부록 1. 프로토타입

1. [[Prototype]] (a.k.a proto)


2. prototype 프로퍼티

var john = new Person(‘john’); john.getName(); //john이 출력된다. getName 함수는 Person의 prototype에 정의되어있다. var jane = new Person(‘jane’); jane.getName(); //jane이 출력된다. john과 jane이 prototype을 통해 getName 함수를 사용한다.

 - 참고 : https://developer.mozilla.org/ko/docs/Web/JavaScript/Inheritance_and_the_prototype_chain

<br/>
<br/>
<br/>

### 부록 2. Lexical Scope
 - JavaScript는 Lexical Scope(또는 Static Scope)를 따르고 있습니다.
 - Lexical Scope란 함수를 어디서 선언하였는지에 따라 상위 스코프를 결정하는 것입니다. 여기서 중요한 점은 함수의 호출 이 아니라 함수의 선언에 따라 결정된다는 점입니다.

### 예제
```js
var number = 1;

function a() {
  var number = 10;
  b();
}

function b() {
  console.log(number);
}

a(); // ?
b(); // ?




부록 3. this 바인딩 활용 예제

var logger = {
    name: "myLogger",
    log: function(txt) {
        console.log(this.name+":", txt);
    }
};

logger.log("Hello there") // myLogger: Hello there
//You may want to pass log as a callback to forEach to log a whole array of elements:

var messages = ["first message", "second message", "third message"];
messages.forEach(function(msg) {
    logger.log(msg);
});

//The simpler way to say that is:

messages.forEach(logger.log.bind(logger));
//messages.forEach(logger.log); // 이렇게 실행할 경우 this는 window가 됨.
정규표현식으로 시간 절약하기
당신의 하루에 몇 시간을 더하세요
WPF MVVM 패턴, 그리고 Binding
WPF(Windows Presentation Foundation) 시리즈
AWS SAA 준비 - (4) 비용에 최적화된 아키텍처 설계
(정리) Exam Readiness - AWS Solutions Architect Associate
AWS SAA 준비 - (3) 안전한 아키텍처
(정리) Exam Readiness - AWS Solutions Architect Associate
AWS SAA 준비 - (2) 성능이 뛰어난 아키텍처 설계
(정리) Exam Readiness - AWS Solutions Architect Associate
AWS SAA 준비 - (1) 복원력을 갖춘 아키텍처 설계
(정리) Exam Readiness - AWS Solutions Architect Associate
15분 안에 ToC를 구현해보자!
Vanilla JS로 Table of Contents 구현하기
모듈
모던 자바스크립트 Deep Dive | 48장 | 모듈
에러 처리
모던 자바스크립트 Deep Dive | 47장 | 에러 처리
제너레이터와 async/await
모던 자바스크립트 Deep Dive | 46장 | 제너레이터와 async/await
프로미스
모던 자바스크립트 Deep Dive | 45장 | 프로미스
REST API
모던 자바스크립트 Deep Dive | 44장 | REST API
Ajax
모던 자바스크립트 Deep Dive | 43장 | Ajax
비동기 프로그래밍
모던 자바스크립트 Deep Dive | 42장 | 비동기 프로그래밍
타이머
모던 자바스크립트 Deep Dive | 41장 | 타이머
Set과 Map
모던 자바스크립트 Deep Dive | 37장 | Set과 Map
디스트럭처링
모던 자바스크립트 Deep Dive | 36장 | 디스트럭처링
브라우저의 렌더링 과정
모던 자바스크립트 Deep Dive | 38장 | 브라우저의 렌더링 과정
스프레드 문법
모던 자바스크립트 Deep Dive | 35장 | 스프레드 문법
이터러블
모던 자바스크립트 Deep Dive | 34장 | 이터러블
7번째 데이터 타입 Symbol
모던 자바스크립트 Deep Dive | 33장 | 7번째 데이터 타입 Symbol
String
모던 자바스크립트 Deep Dive | 32장 | String
RegExp
모던 자바스크립트 Deep Dive | 31장 | RegExp
Date
모던 자바스크립트 Deep Dive | 30장 | Date
Math
모던 자바스크립트 Deep Dive | 29장 | Math
DOM
모던 자바스크립트 Deep Dive | 39장 | DOM
Number
모던 자바스크립트 Deep Dive | 28장 | Number
배열
모던 자바스크립트 Deep Dive | 27장 | 배열
이벤트
모던 자바스크립트 Deep Dive | 40장 | 이벤트
ES6 함수의 추가 기능
모던 자바스크립트 Deep Dive | 26장 | ES6 함수의 추가 기능
클래스
모던 자바스크립트 Deep Dive | 25장 | 클래스
this
모던 자바스크립트 Deep Dive | 22장 | this
빌트인 객체
모던 자바스크립트 Deep Dive | 21장 | 빌트인 객체
strict mode
모던 자바스크립트 Deep Dive | 20장 | strict mode
클로저
모던 자바스크립트 Deep Dive | 24장 | 클로저
프로토타입
모던 자바스크립트 Deep Dive | 19장 | 프로토타입
함수와 일급 객체
모던 자바스크립트 Deep Dive | 18장 | 함수와 일급 객체
실행 컨텍스트
모던 자바스크립트 Deep Dive | 23장 | 실행 컨텍스트
생성자 함수에 의한 객체 생성
모던 자바스크립트 Deep Dive | 17장 | 생성자 함수에 의한 객체 생성
프로퍼티 어트리뷰트
모던 자바스크립트 Deep Dive | 16장 | 프로퍼티 어트리뷰트
let, const 키워드와 블록 레벨 스코프
모던 자바스크립트 Deep Dive | 15장 | let, const 키워드와 블록 레벨 스코프
전역 변수의 문제점
모던 자바스크립트 Deep Dive | 14장 | 전역 변수의 문제점
스코프
모던 자바스크립트 Deep Dive | 13장 | 스코프
함수
모던 자바스크립트 Deep Dive | 12장 | 함수
원시 값과 객체의 비교
모던 자바스크립트 Deep Dive | 11장 | 원시 값과 객체의 비교
객체 리터럴
모던 자바스크립트 Deep Dive | 10장 | 객체 리터럴
타입 변환과 단축 평가
모던 자바스크립트 Deep Dive | 9장 | 타입 변환과 단축 평가
제어문
모던 자바스크립트 Deep Dive | 8장 | 제어문
연산자
모던 자바스크립트 Deep Dive | 7장 | 연산자
데이터 타입
모던 자바스크립트 Deep Dive | 6장 | 데이터 타입
표현식과 문
모던 자바스크립트 Deep Dive | 5장 | 표현식과 문
변수
모던 자바스크립트 Deep Dive | 4장 | 변수
Iteration와 Generator
코드스피츠 77 ES6+ 3화 참조
WHATWG 탄생 배경
WHATWG, W3C, HTML의 관련에 대한 역사
프론트엔드(FE) 면접 질문 정리
FE관련 면접 질문 및 답변 정리한 내용입니다.
쿠버네티스(kubernetes, k8s) 용어 정리
쿠버네티스(kubernetes, k8s) 용어 정리
젠킨스(Jenkins) 정리
젠킨스(Jenkins) 정리
Docker 용어 정리
Docker 용어 정리
Git 용어 정리
Git 용어 정리
반응형 웹 디자인(Responsive Web Design)
CSS responsive 에 대하여
JS this에 대하여
this에 대해 알아보자
SQL*PLUS에 대하여
SQL*PLUS 정의 및 사용방법
Oracle에서 SQL Plan 확인하기
Oracle에서 SQL Plan을 확인해보자