ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 22장. this
    책/모던 자바스크립트 딥다이브 2022. 5. 9. 22:34

    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
킹수빈닷컴