티스토리 뷰

22장. this

22-1. this 키워드

function Circle(radius) {
    // 이 시점에는 생성자 함수 자신이 생성할 인스턴스를 가리키는 식별자 모름.
    ????.radius = radius;
}

Circle.prototype.getDiameter = function() {
    // 이 시점에는 생성자 함수 자신이 생성할 인스턴스를 가리키는 식별자 모름.
    return 2 * ????.radius;
}

const circle = new Circle(5);
  • 생성자 함수를 정의하는 시점에는 아직 인스턴스 생성 이전이므로 생성할 인스턴스를 가리키는 식별자를 알 수 없다. 따라서 자신이 속한 객체 또는 생성할 인스턴스를 가리키는 특수한 식별자가 필요한데 이를 위해 JS는 this 라는 특수한 식별자를 제공한다.
  • this 는 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수(self-referencing variable)이다.
  • this 를 통해서 자신이 속한 객체 또는 자신이 생성할 인스턴스의 프로퍼티나 메서드를 참조할 수 있다.
  • this 는 JS 엔진에 의해 암묵적 생성, 어디서든 참조 가능하다.
  • 함수 호출시 arguments 객체와 this 가 암묵적으로 함수 내부에 전달된다.
  • this 가 가리키는 값, 즉 this 바인딩은 함수 호출 방식에 의해 동적으로 결정된다.
// 객체 리터럴 메서드 내부의 this는 메서드를 호출한 객체를 가리킨다.
const circle = {
    radius: 5,
    getDiameter() {
    return 2 * this.radius;	
    }
}

// 생성자 함수 내부의 this는 생성자 함수가 생성할 인스턴스를 가리킨다.
function Circle(radius) {
    this.radius = radius;
}

Circle.prototype.getDiameter = function() {
    return 2 * this.radius;
}

22-2. 함수 호출 방식과 this 바인딩

const foo = function() {
    console.dir(this);
};

// 일반 함수 호출
foo(); // window

// 메서드 호출
const obj = { foo };
obj.foo(); // obj

// 생성자 함수 호출
new foo(); // foo {}

// 간접 호출
const bar = { name: 'bar' };

foo.call(bar);
foo.apply(bar);
foo.bind(bar);

일반 함수 호출

  • 기본적으로 this 에는 전역 객체가 바인딩된다.
  • 어떠한 함수라도 일반 함수로 호출되면 this에 전역 객체가 바인딩 된다.
// 일반
function foo() {
    console.log(this); // window
    function bar() {
        console.log(this); // window
    }
    bar();
}
foo();

// strict mode
function foo() {
    'use strict';

    console.log(this); // undefined
    function bar() {
        console.log(this); // undefined
    }
    bar();
}
foo();
var value = 1;

const obj = {
    value: 100,
    foo() {
        console.log(this); // { value: 100, foo: f }
        console.log(this); // 100

        function bar() {
            console.log(this); // window
            console.log(this); // 1
        }
		
        // 메서드 내에서 정의한 중첩 함수도 일반 함수로 호출되면 중첩 함수 내부의 this에는
        // 전역 객체가 바인딩된다.
        bar(); 
    }
};

obj.foo();
var value = 1;

const obj = {
    value: 100,
    foo() {
        console.log(this); // { value: 100, foo: f }

        // 콜백 함수 내부의 this에는 전역 객체가 바인딩된다.
        setTimeout(function() {
            console.log(this); // window
            console.log(this); // 1
        }, 100);
    }
};

obj.foo();
  • 메서드 내부의 중첩 함수나 콜백 함수의 this 바인딩을 메서드의 this 바인딩과 일치시키기 위한 방법
// 1. 따로 변수 만들어 바인딩
var value = 1;

const obj = {
    value: 100,
    foo() {
        // this 바인딩(obj)을 변수 that 에 할당
        const that = this;

        // 콜백 함수 내부에서 this 대신 that 을 참조한다.
        setTimeout(function() {
            console.log(that.value); // 100
        }, 100);
    }
};

obj.foo(); 

// 2. Function.prototype.apply, call, bind 사용하여 명시적 바인딩
var value = 1;

const obj = {
    value: 100,
    foo() {
        // 콜백 함수에 명시적으로 this를 바인딩한다.
        setTimeout(function() {
            console.log(this.value); // 100
        }.bind(this), 100);
    }
};

obj.foo(); 

// 3. 화살표 함수 사용하여 바인딩
var value = 1;

const obj = {
    value: 100,
    foo() {
        // 화살표 함수 내부의 this는 상위 스코프의 this를 가리킨다.
        setTimeout(() => console.log(this.value), 100); // 100
    }
};

obj.foo();

메서드 호출

  • 메서드 내부의 this에는 메서드를 호출한 객체, 즉 메서드를 호출할 때 메서드 이름 앞의 . 연산자 앞에 기술한 객체가 바인딩 된다.
// 1
const anotherPerson = {
    name: 'Lee'
};
anotherPerson.getName = person.getName;

console.log(anotherPerson.getName()); // Lee

// 2
const getName = person.getName;

console.log(getName()); // '' -> 브라우저 환경 '', Node환경 undefined
// 프로토타입 메서드 내부에서 사용된 this도 일반 메서드와 마찬가지
function Person(name) {
    this.name = name;
}

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

const me = new Person('Lee');

console.log(me.getName()); // Lee

Person.prototype.name = 'Kim';

console.log(Person.prototype.getName()); // Kim

생성자 함수 호출

  • 생성자 함수 내부의 this에는 생성자 함수가 생성할 인스턴스가 바인딩 된다.

Function.prototype.apply/call/bind 메서드에 의한 간접 호출

  • apply, call, bind 메서드는 Function.prototype의 메서드여서 모든 함수가 상속받아 사용할 수 있다.
function getThisBinding() {
    return this;
}

const thisArg = { a: 1 };

console.log(getThisBinding()); // window
console.log(getThisBinding.apply(thisArg)); // { a: 1 }
console.log(getThisBinding.call(thisArg)); // { a: 1 }

정리

함수 호출 방식 this 바인딩

일반 함수 호출 전역 객체
메서드 호출 메서드를 호출한 객체
생성자 함수 호출 생성자 함수가 생성할 인스턴스
Function.prototype.apply/call/bind 메서드에 의한 간접 호출 메서드에 첫 번째 인수로 전달한 객체

' > 모던 자바스크립트 딥다이브' 카테고리의 다른 글

45장. 프로미스  (3) 2022.05.14
44장. REST API  (0) 2022.05.14
19장. 프로토타입  (0) 2022.04.30
18장. 함수와 일급 객체  (2) 2022.04.24
17장. 생성자 함수에 의한 객체 생성  (0) 2022.04.24