코드노트

자바스크립트 this 이해하기 본문

Code note/자바스크립트

자바스크립트 this 이해하기

코드노트 2022. 12. 21. 00:40

 

생성자 함수를 예로들어보자.

 

생성자 함수 내부에서 프로퍼티, 메서드를 추가하려면 자신이 생성하는 인스턴스를 참조할 수 있어야한다.

* 참조할 수 있지만 함수 이름을 통해서 재귀적으로 참조하는 방식은 바람직하지 않은 방법 - this를 사용

 

this

- 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수(self-referencting variable)

- this를 통해 자신이 속한 객체 또는 자신이 생성할 인스턴스의 프로퍼티 또는 메서드를 참조

 

- JS 엔진에 의해서 암묵적으로 생성

- 어느 코드에서나 참조 가능

- 함수 호출시 arguments객체와 this가 암묵적으로 함수 내부에 전달

- 지역 변수처럼 사용할 수 있다.

- this가 가리키는 값은? this바인딩, 함수 호출 방식에 의해 동적으로 결정


바인딩?

- 식별자와 값을 연결하는 과정을 의미

- this 바인딩 : this와 this가 가리키는 객체를 바인딩하는 것


this 예제

const traveler = {
  first: "곽튜브",
  sayHi() {
    return `Hi ${this.first}`; // this는 메서드를 호출한 객체
  },
};

console.log(traveler.sayHi()); // Hi 곽튜브

- 객체 리터럴 메서드 내부에서 this는 메서드를 호출하는 객체를 가리키고 있다. traveler

 

function Traveler(name) {
  this.name = name; // this는 생성자 함수가 생성할 인스턴스
}

Traveler.prototype.sayHi = function () {
  return `Hi ${this.name}`; // this는 생성자 함수가 생성할 인스턴스
};

const frist = new Traveler("곽튜브");
console.log(frist.sayHi()); // Hi 곽튜브

- 생성자 함수 내부에서는 생성자 함수가 생성할 인스턴스를 가리킨다. 


- JS에서 this는 함수가 호출되는 방식에 따라 this에 바인딩되는 값이 동적으로 결정된다.


- 어떠한 함수라도 일반함수로 호출되면 this에 전역 객체가 바인딩 된다.

* (메서드 내에 정의한 중첩함수라도 일반함수라면 전역 객체)

- 중첩 함수 또는 메서드에게 전달한 콜백함수가 일반함수로 호출될 때 메서드 내에서 this가 전역 객체를 바인딩하는 것은 문제가 있다.

 

이 문제를 해결하려면!?

 

let value = 1;

const obj = {
  value: 100,
  foo() {
    const here = this; // this를 변수에 할당 한다.

    setTimeout(function () {
      console.log(here.value); // 100
    }, 100);
  },
};

obj.foo();

- this바인딩을 변수에 할당해서 사용!

 

- 그 외에도 apply, call, bind를 사용할 수 있다.

- 화살표 함수를 사용해서 바인딩하면  this 바인딩을 일치시킬 수 있다.( 화살표 함수 내부의 this는 상위 스코프의 this를 가르킨다.)


메서드 호출 시 메서드 내부의 this는

메서드를 소유한 객체가 아닌 메서드를 호출한 객체에 바인딩 된다.

const traveler = {
  name: "곽튜브",
  sayHi() {
    return `Hi ${this.name}`;
  },
};

console.log(traveler.sayHi()); // Hi 곽튜브

const secondTraveler = {
  name: "빠니보틀",
};

secondTraveler.sayHi = traveler.sayHi; // 메서드 할당

console.log(secondTraveler.sayHi()); // Hi 빠니보틀

- 메서드를 호출한 객체에 바인딩된 것을 볼 수 있다. 

 

- 프로토타입에 추가하여 사용하게 되면 직접 호출할 수 있다. ( 호출 시점 )


생성자 함수 호출

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

function Traveler(name) {
  this.name = name;
  this.sayHi = function () {
    return `Hi ${this.name}`;
  };
}

const first = new Traveler("곽튜브");
const second = new Traveler("빠니보틀");

console.log(first.sayHi()); // Hi 곽튜브
console.log(second.sayHi()); // Hi 빠니보틀

- 만약 new 연산자와 함께 생성자 함수를 호출하지 않으면 생성자 함수가 아니라 일반 함수로 동작


apply / call / bind

Function.prototype.XXX

- apply, call, bind 메서드는 함수가 상속 받아 사용

 

apply, call

function getThisBinding() {
  console.log(arguments);
  return this;
}

console.log(getThisBinding()); // window, vsCode에서는 Object

const thisArg = { a: 1 };

// apply, call 메서드는 함수를 호출하는 메서드
console.log(getThisBinding.apply(thisArg)); // { a: 1 }
console.log(getThisBinding.call(thisArg)); // { a: 1 }

// 인수로 전달하는 객체를 getTisBinding함수의 this로 바인딩
console.log(getThisBinding.apply(thisArg, [1, 2, 3]));
// [Arguments] { '0': 1, '1': 2, '2': 3 }
// { a: 1 }
console.log(getThisBinding.call(thisArg, 1, 2, 3));
// [Arguments] { '0': 1, '1': 2, '2': 3 }
// { a: 1 }

- apply, call의 기능은 함수를 호출하는 것

- 함수를 호출하면서 첫 번째 인수로 전달한 특정 객체를 호출한 함수의 this에 바인딩 한다.

 

- apply 메서드는 호출할 함수의 인수를 배열로 전달

- call 메서드는 호출할 함수의 인수를 쉼표로 구분한 리스트 형식으로 전달

 

- 위 코드를 참고하면 호출할 함수에 인수를 전달하는 방식만 다를 뿐 this로 사용할 객체를 전달하면서 함수를 호출하는 것은 동일

 

 

그럼 여기서 인수만 전달 해서 배열만 사용할 수 없을까?!!!

 

function convertArgsToArray() {
  const arr = Array.prototype.slice.call(arguments);
  // const arr = Array.prototype.slice.apply(arguments)

  console.log(arr);
  return arr;
}
convertArgsToArray(1, 2, 3); // [ 1, 2, 3 ]

- 위와 같이 사용 가능하다.


bind() 는 함수를 호출하지 않는다.

- 첫번째 인수로 전달한 값으로 this 바인딩이 교체된 함수를 새롭게 생성하여 반환

- 콜백함수의 this가 불일치하는 문제를 해결하는데 유용하게 사용 가능

- 함수를 호출하지 않으므로 명시적으로 호출 bind(this)

const traveler = {
  name: "곽튜브",
  foo(callback) {
    setTimeout(callback.bind(this), 100);
  },
};

traveler.foo(function () {
  console.log(`Hi ${this.name}`); // Hi 곽튜브
});

- 콜백함수는 외부 함수를 도울때 헬퍼 함수 역할을 하기 때문에 내부의 this와 콜백 함수 내부의 this가 다르게 되면 문맥상 문제가 발생

- 콜백 함수 내부의 this외부 함수 내부의 this와 일치 시켜야할 때 사용할 수 있다.



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