Deep Dive 22장 This

@hanminss·2021년 12월 13일
0

Deep Dive

목록 보기
12/16
post-thumbnail

1. this 키워드

  • 객체는 상태를 나타내는 프로퍼티와 동작을 나타내는 메서드를 하나의 논리적인 단위로 묶은 복합적인 자료구조다.
  • 메서드는 자신ㅇ이 속한 택체의 상태를 변경할 수 있어야 하여 자신이 속한 객체를 가리키는 식별자를 참조할 수 있어야 한다.
  • 리터럴 방식의 객체는 메서드에서 재귀적으로 참조할 수 있지만 일반적이지 않으며 바람직하지 않은 방법이다.
const circle = {
  radius: 5,
  getDiameter() {
    return 2 * circle.radius; // 재귀
  },
};

console.log(circle.getDiameter());
  • 자바스크립트는 this라는 특수한 자기참조 변수를 제공한다.
  • this는 js 엔진에 의해 암묵적으로 생성되며 함수를 호출하면 arguments 객체와 this가 암묵적으로 함수 내부에 전달된다.
  • this가 가리키는 값인 this 바인딩은 함수 호출 방식에 의해 동적으로 결정된다.

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

  • 함수의 호출 방식
    1. 일반함수 호출
    2. 메서드 호출
    3. 생성자 함수 호출
    4. Function.prototype.apply/call/bind 에 의한 간접호출
// 일반함수 호출
const foo = function () {
  console.log(this);
};
foo();
/* <ref *1> Object [global] {
  global: [Circular *1],
  clearInterval: [Function: clearInterval],
  clearTimeout: [Function: clearTimeout],
  setInterval: [Function: setInterval],
  setTimeout: [Function: setTimeout] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  },
  queueMicrotask: [Function: queueMicrotask],
  clearImmediate: [Function: clearImmediate],
  setImmediate: [Function: setImmediate] {
    [Symbol(nodejs.util.promisify.custom)]: [Getter]
  }
  일반함수는 global 객체를 가리킨다.
} */

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

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

일반 함수 호출

  • 기본적으로 this에는 전역 객체가 바인딩된다.
  • strict mode가 적용되면 undefined가 바인딩 된다.
function foo() {
  console.log("foo's this:", this);//  global
  function bar() {
    console.log("bar's this:", this); // global
  }
  bar();
}

foo();
  • 메서드 내에서 정의한 중첩 함수도 this에 전역 객체가 바인딩 된다.
  • 어떤 함수라도 일반 함수로 호출되는 this에 전역 객체가 바인딩 된다.

var value = 1;

const obj = {
  value: 100,
  foo() {
    console.log("foo's this:", this); // obj
    setTimeout(function () {
      console.log("callback's this:", this); // window
      console.log("callback's value:", this.value); // 1
    }, 100);
  },
};

obj.foo();
  • 메서드 내부의 중첩함수는 콜백함수의 this 바인딩을 일치시키는 방법
    1. this를 변수에 할당

      var value = 1;
      
      const obj = {
        value: 100,
        foo() {
          const that = this;
          setTimeout(function () {
            console.log("callback's that:", that); //{ value: 100, foo: [Function: foo] }
            console.log("callback's value:", that.value); //100
      
          }, 100);
        },
      };
      
      obj.foo();
    2. bind 사용

      var value = 1;
      
      const obj = {
        value: 100,
        foo() {
          setTimeout(
            function () {
              console.log("callback's that:", this); //{ value: 100, foo: [Function: foo] }
              console.log("callback's value:", this.value); //100
            }.bind(this),
            100
          );
        },
      };
      
      obj.foo();
    3. 화살표함수 사용( 화살표 함수 내부의 this는 상위 스코프의 this를 가리킨다.)

      var value = 1;
      
      const obj = {
        value: 100,
        foo() {
          setTimeout(() => console.log(this.value), 100); // 100
        },
      };
      
      obj.foo();

메서드 호출

  • 메서드 내부의 this는 메서드를 소유한 객체가 아닌 메서드를 호출한 객체에 바인딩된다.
  • 메서드는 객체에 포함된것이 아닌 독립적으로 존재하는 별도의 객체다. 메서드 프로퍼티가 함수 객체를 가리키고 있다.
const person = {
  name: "Yim",
  getName() {
    return this.name;
  },
};

console.log(person.getName());
// getName을 호출한 객체는 person 이다.

const anotherPerson = {
  name: "Kim",
};

anotherPerson.getName = person.getName; // 메서드 할당

console.log(anotherPerson.getName());

const getName = person.getName;

console.log(getName()); // window.name

생성자 함수 호출

  • 생성자 함수 내부의 this에는 생성자 함수가 생성할 인스턴스가 바인딩된다.
  • new 가없으면 일반함수처럼 this가 동작한다.

Function.prototype.apply/call/bind

  • 세 메서드는 함수의 프로토타입 메서드 이기 때문에 모든 함수가 상속받아 사용할 수 있다.
  • apply와 call 은 this로 사용할 객체와 argument를 인수로 받는다. apply와 call의 차이점은 apply는 argument를 배열로 받고 call은 쉼표로 구분해서 전달한다.
  • bind는 this 로 사용할 객체만을 보낸다..
  • apply,call 과 bind의 차이점은 함수의 호출 유무이다. bind는 함수를 호출하진 않는다.
function getThisBinding() {
  console.log(arguments);
  return this;
}

const thisArg = { a: 1 };
console.log(getThisBinding);
console.log(getThisBinding.apply(thisArg, [1, 2, 3]));
// [Arguments] { '0': 1, '1': 2, '2': 3 }
// { a: 1 }

console.log(getThisBinding.call(thisArg, 1, "zz", 3));
// [Arguments] { '0': 1, '1': 'zz', '2': 3 }
// { a: 1 }

console.log(getThisBinding.bind(thisArg));
//[Function: bound getThisBinding] 호출이 안된다.

console.log(getThisBinding.bind(thisArg)());
// /[Arguments] {}
// { a: 1 }

0개의 댓글