자바스크립트에서 this 란 '나' 라는 단어와 비슷합니다. 어떤 문맥이냐에 따라서 그 의미(값)이 바뀜니다.

var name = 'window name';

function log() {
	console.log(this.name); // 'this' is always an object
}

var obj = {
	name: 'ken',
	logName: log,
}

log();                // this : window ★★★ (window 객체에 의해 호출 - 내부적으로)
obj.logName();        // this : obj    ★★★ (obj 객체에 의해 호출)

'this' 의 값은 'this' 를 사용하는 해당 함수를 "어떻게 실행"하느냐에 따라 바뀜니다.

(혼동 주의 : 호출된 변수 X!, 호출된 함수 O!)

함수를 실행하는 방법엔 크게 4가지가 있습니다.

(this 를 이용하는) 해당 함수를 이 4가지 중 어떤 방식으로 실행하느냐에 따라 this 의 값은 바뀜니다.

  1. Regular function call : 일반 함수 실행 방식

    function foo() {
    	console.log(this); *// 'this' === global object (브라우저상에선 window 객체)*
    }
    
    foo(); *// 일반 함수 실행 방식*
    
    'use strict';
    function foo() {
    	console.log(this); *// 'this' === undefined*
    }
    
    foo(); *// 일반 함수 실행 방식
    // 'use strict' 사용 시 this -> undefined
    // window.(변수 및 함수); 이렇게 window 라고 명시해 주어야 됨
    
    // [ 보충 설명 ]
    // var 나 function 은 global 객체인 window 객체에서 접근이 가능하나
    // let, const 의 경우 window 객체에서 접근이 불가능하다.*
    
    var age = 100;
    
    function foo() {
      var age = 99;
      bar();
    }
      
    function bar() {
      console.log(this.age);
    }
    
    foo(); *// 일반 함수 실행 방식* 
    		   *// (this.age === 100 / this === window)*
    
  2. Dot Notation - 점 방식 (함수 실행 시 점 앞의 객체가 this)

    var age = 100;
    
    var ken = {
      age: 35,
      foo: function () {
        console.log(this.age);
      },
    	too: this,
    };
    
    ken.foo(); *// 객체 실행 방식 (this.age === 35 / this === ken)*
    console.log(ken.too); *// (this === window) 변수는 X, 함수만 O
                          // 변수의 this 가 해당 객체일 때에는 new 로 객체를 생성하였을 때
                          // 즉, 생성자 함수와, 클래스 함수에서 변수의 this 는 해당 객체임*
    
    function foo() {
      console.log(this.age);
    }
    
    var age = 100;
    var ken = {
      age: 35,
      foo,
    };
      
    var wan = {
      age: 31,
      foo,
    };
    
    ken.foo(); *// 객체 실행 방식 (this.age === 35 / this === ken)*
    wan.foo(); *// 객체 실행 방식 (this.age === 31 / this === wan)*
    
    var age = 100;
    
    var ken = {
      age: 35,
      foo: function () {
        console.log(this.age);
      },
    };
    
    var wan = {
      age: 31,
      foo: ken.foo,
    };
    
    var foo = ken.foo;
    
    ken.foo(); *// 객체 실행 방식 (this.age === 35 / this === ken)*
    wan.foo(); *// 객체 실행 방식 (this.age === 35 / this === wan)*
    foo();     *// 일반 함수 실행 방식 (this.age === 100 / this === window)*
    
  3. Function.prototype.call, Function.prototype.apply, Function.prototype.bind

    function foo(a, b) {
      console.log(this.age);
      console.log(arguments);
      console.log(a, b);
    }
    
    var age = 100;
    
    var ken = {
      age: 35,
    	foo,
    };
    var wan = {
      age: 31,
    	foo,
    };
    
    *// call 과 apply 는 바로 선언하여 사용한다.*
    foo.call(ken, [1, 2, 3, 4, 5], 1); *// (this.age === 35 / this === ken)*
    foo.apply(wan, [1, 2, 3, 4, 5]);   *// (this.age === 31 / this === wan)
    
    																	 //* console.log(arguments)
    																	 *// => 0: [1, 2, 3, 4, 5] / 1: 1
    																	 //* console.log(arguments)
    																	 *// => 0: 1/ 1: 2/ 2: 3/ 3: 4/ 4: 5
    
    																	 //* console.log(a, b);
    																	 *// [1, 2, 3, 4, 5] 1
    																	 //* console.log(a, b);
    																	 // 1 2
    
    *// bind 는 변수에 할당하여 사용한다.*
    var bar = foo.bind(ken, 10, 11);
    bar(); *// (this.age === 35 / this === ken)
    
    // ----------------------------
    // bind 다른 예
    
    const bindTest = { name: 'ht' };
    function bindFunc() {
    	console.log(this.name);
    }
    
    const result = bindFunc.bind(bindTest);
    result();
    // ht
    
    bindFunc.bind(bindTest)();
    // ht*
    

    [ call ] → 함수를 호출

    call(this: Function, thisArg: any, ...argArray: any[]): any;

    현재 객체를 다른 객체로 대체하여 객체의 메서드를 호출합니다.

    @param thisArg 는 현재 개체로 사용할 개체입니다.

    @param argArray 는 메서드에 전달할 인수 목록입니다. → (인수 목록)

    [ apply ] → 함수를 호출

    apply(this: Function, thisArg: any, argArray?: any): any;

    지정된 객체를 함수의 this 값으로, 지정된 배열을 함수의 인수로 대체하여 함수를 호출합니다.

    @param thisArg 는 this 객체로 사용할 객체.

    @param argArray 는 함수에 전달할 인수 집합입니다. → (인수 집합)

    [ bind ] → 함수문 반환

    bind(this: Function, thisArg: any, ...argArray: any[]): any;

    주어진 함수에 대해 원래 함수와 본문이 동일한 바인딩된 함수를 만듭니다.

    바인딩된 함수의 this 개체는 지정된 개체와 연결되며 지정된 초기 매개변수를 갖습니다.

    @param thisArg 는 this 키워드가 새 함수 내에서 참조할 수 있는 개체입니다.

    @param argArray 는 새 함수에 전달할 인수 목록입니다. → (인수 목록)

    ※ 즉 해당 [함수]를 해당 [객체]로 바인딩 한다. 는 의미이다.

    함수.call(바인딩할 객체, 인수, ...);

    함수.apply(바인딩할 객체, 인수, ...);

    함수.bind(바인딩할 객체, 인수, ...);

  4. 'new' keyword

    *// 생성자 함수*
    function Foo() {
      *//this = {}; (내부적으로 동작)* 
      console.log(this);
    	this.name = this;
      *//return this; (내부적으로 동작)*
    }
    
    new Foo();  *// new Foo() 선언 시 this 에 Foo 객체 할당
                // this === Foo*
    

    생성자 함수와 마찬가지로, 클래스 함수에서도 this = {} / return this 처럼 동일하다.

  5. 예외 (Event Handler)

    const element = document.querySelector('#vanila');
    element.addEventListener('click', function onClick (event) {
    	console.log(this);                // 지양(헷갈리게 만든다)
    	console.log(event.target);        // 지향(상황에 따라)
    	console.log(event.currentTarget); // 지향(상황에 따라)
    });
    

문제)

정답보기

예제( class 에서 this → 생성자 함수와 동일 )

class Counter {
  count = this;
  increase = function () {
    console.log(this);
  };

  increase2 = () => { // bind 방법2 (Arrow function 사용)
    console.log(this);
  };
}

const counter = new Counter();
console.log(counter.count); // this -> Counter

counter.increase(); // this -> Counter

const caller = counter.increase;
caller(); // this -> undefined

const caller2 = counter.increase.bind(counter); // bind 방법1 (bind 함수 사용)
caller2(); // this -> Counter

const caller3 = counter.increase2;
caller3(); // this -> Counter

class Bob { }
const bob = new Bob();
bob.run = counter.increase;
bob.run(); // this -> Bob