자바스크립트 This 란?

hoo00nn·2021년 1월 4일
0
post-thumbnail

이번 포스팅에선 자바스크립트 This의 대해서 알아보겠다.
코어 자바스크립트의 내용을 학습하고 정리한 글이다.

This 란?

이전에 실행 컨텍스트에 대해 학습하면서 실행 컨텍스트가 언제 생성되는지 알 수 있었다.

또한, ThisBinding이 실행 컨텍스트에서 이루어진다는 것도 알 수 있었다.

This"어떻게" 호출되는지에 따라 달라진다.

즉, 함수를 실행하는 주체가 누구인지에따라 달라지게 되는 것이다.

호출되는 방식에 따라 5가지로 구분할 수 있다.

  • 전역공간에서
  • 함수 호출 시
  • 메소드 호출 시
  • callback 호출 시
  • 생성자함수 호출 시

전역공간에서

전역 공간에서 this 는 브라우저에선 window , Node.js에선 global 을 가리킨다.

개념상으로 전역 컨텍스트를 호출하는 주체가 전역객체이기 때문이다.

// 브라우저
console.log(this) // window

// 노드
console.log(this) // global

함수 호출 시

함수 호출 시 this 는 브라우저에선 window , Node.js에선 global 을 가리킨다.

첫 번째 코드의 경우 전역 공간에서 함수를 호출했기 때문에 this 가 window 또는 global을 가리키는 것은 알겠다.

하지만 두 번째 코드에서는 뭔가 조금 이상하다. b 함수의 경우 전역 공간에서 실행했으니 window 또는 global을 가리키겠지만, b 함수 내부에서 호출한 c 함수 또한 window 또는 global을 가리킨다.

이거는 자바스크립트를 빠르게 만들다보니 생긴 실수라고 얘기한다. 이것을 버그라고 봐야할지 자바스크립트만의 특성이라고 봐야할지 의견이 분분하다.

그렇기 때문에 ES6+ 에서는 this 바인딩을 하지않는 Arrow Function 이란 것이 나왔다. Arrow Function 을 사용하면 상위 컨텍스트의 this를 사용하게되어 이 문제를 해결할 수 있다.

// 첫 번째 코드
function a() {
  console.log(this);
}

a(); // window , global

// 두 번째 코드
function b() {
  function c() {
    console.log(this);
  }
  
  c();
}

b(); // window , global

메소드 호출 시

메소드를 호출했을 시 this 는 메소드의 호출 주체(메소드명 앞)이 된다.

var a = {
  b: function() {
    console.log(this);
  }
}

a.b(); // this -> a
var a = 10;
var obj = {
  a: 20,
  b: function() {
    console.log(this.a);  // 20
	
    function c() {
      console.log(this.a);  // 10
    }
    
    c();
  }
}

obj.b();

만약 우리가 c 함수를 호출했을 때 원하는 결과가 20이라면 어떻게 해야할까?

방법은 두 가지가 있다.

  1. Arrow Function을 사용
  2. b 내부에서 this를 변수에 저장
// 1번
var a = 10;
var obj = {
  a: 20,
  b: function() {
    console.log(this.a);  // 20
	
    const c = () => {
      console.log(this.a);  // 20
    }
    
    c();
  }
}

obj.b();

// 2번
var a = 10;
var obj = {
  a: 20,
  b: function() {
    const self = this;
    console.log(this.a);  // 20
	
    function c() {
      console.log(self.a);  // 20
    }
    c();
  }
}

obj.b();

callback 호출 시

callback 호출 시 this 는 기본적으로 함수내부에서와 동일하다.

let callback = function() {
  console.log(this);
}

let obj = {
  a: 1,
  b: function(cb) {
    cb();
  }
}

obj.b(callback);

아래 코드에서의 this 는 무엇일까?

let callback = function() {
  console.log(this);
}

let obj = {
  a: 1,
  b: function(cb) {
    cb.call(this);
  }
}

obj.b(callback);

생성자함수 호출 시

new 키워드를 통해 생성자함수 호출 시 this 는 인스턴스를 가리킨다.

즉, 생성자함수 호출 시 객체가 만들어지고, 객체가 this가 되는 것이다.

function Who(name, age) {
  this.name = name;
  this.age = age;
}

let jihoon = new Who('hoo00nn', '26ㅠㅠ');

console.log(jihoon);
/*

Who {
  name: 'hoo00nn',
   age: '26ㅠㅠ'
}

*/

Explict Binding

함수도 일급객체이기 때문에 메소드를 사용할 수가 있다.

언제, 어디에서든 call, apply, bind 메소드들을 사용해서 함수를 실행시킬 수 있는데, 함수가 호출될 컨텍스트를 지정하여 함수를 호출할 수 있게 한다.

이것이 바로 명시적 바인딩이다. this 키워드가 무엇을 참조할 지 명시적으로 알려주는 방법이다.

call 과 apply는 함수를 즉시 호출하고

bind는 this를 바인딩한 새로운 함수를 리턴한다.

function greeting() {
  console.log(`My name is ${name}`);
}

const obj = {
  name: 'hoo00nn',
}

greeting(); // undefined
greeting.call(user); // My name is hoo00nn

만약 함수의 파라미터가 있다면 어떻게 사용해야할까?

call 함수의 첫번째 인자로 컨텍스트를 넣은 다음, 차례대로 인자를 넣어주면 된다.

function greeting(a, b, c) {
  console.log(`My name is ${name} and I know ${a}, ${b}, ${c}`);
}

const language = ['JavaScript', 'Python', 'Java'];

const obj = {
  name: 'hoo00nn',
}

greeting(); // undefined
greeting.call(user, language[0], language[1], language[2]); 
// My name is hoo00nn and I know JavaScript, Python, Java

만약 인자를 차례로 넣기 귀찮다면 apply 메소드를 사용하여 배열로 한번에 넣을 수 있다.

const language = ['JavaScript', 'Python', 'Java'];

greeting.apply(user, language);

bind 는 새로운 함수를 반환한다.

1. 원본 함수를 복제한 "새로운 함수"를 반환해줄뿐 함수를 실행하지 않으며

2. 반환된 함수를 실행해야 원본함수가 실행된다.

3. 첫번째 인자는 this값이 되고

4. 전달할 수 있는 인자의 갯수 제한이 없다.

function greeting(a, b, c) {
  console.log(`My name is ${name} and I know ${a}, ${b}, ${c}`);
}

const language = ['JavaScript', 'Python', 'Java'];

const obj = {
  name: 'hoo00nn',
}

// this = obj, a = 'JavaScript', b = 'Python'
let newFunc = greeting.bind(user, language[0], language[1]); 

// c = 'Java', 복사본 함수에게 주어지는 인자도 순차적으로 원본함수에게 전달되기 때문.
newFunc(language[2]); 
profile
😀 신기술에 관심이 많고, 함께 성장하고 함께 개발하고 싶은 개발자가 되고 싶습니다. 😀

0개의 댓글