호다닥

Javascript : 초보자를 위한 'This' 본문

Javascript

Javascript : 초보자를 위한 'This'

3jun 2018. 7. 17. 22:12

The Keyword ‘This’ for Beginners

출처 : codeburst.io, Brandon Morelli

해당 내용은 Brandon Morelli의 article을 개인적으로 번역한 내용이며, 잘못 번역된 부분이 있을 수 있습니다. 원문은 위에 적힌 주소에서 확인하실 수 있습니다.

 

This 는 다소 복잡한 개념이지만, 이제부터 설명할 5가지 일반적인 법칙을 이해한다면 this 를 어떻게 사용할지, 언제 사용할 지 결정하는데 도움이 될 것이다. 

물론 이 법칙들이 모든 경우를 설명할 수 있는 것은 아니지만 특수한 경우를 제외하면 대부분의 상황에서 도움이될 것이다. 

 

 

#Global Object

크롬 개발자 콘솔을 열고 Console.log(this); 를 입력하면 // Window {...} 가 출력된다.

전역스코프에서 this는 global object를 의미하기 때문에 window 객체가 출력되는 것이다. 

브라우저에서 global object는 window object이다. 

 

this가 왜 window object를 나타내는지 좀더 자세히 이해하기 위해 좀 더 깊게 들어가보자. 

콘솔에서 새로운 변수를 만들고 변수에 이름을 할당한다. 

 

var myName = 'Jun';

 

우리는 변수 호출을 통해 이 새로운 변수를 가져올 수 있다. 

 

myName

// returns -> 'Jun'

 

전역스코프에서 선언한 모든 변수는 window object가 된다. 

 

window.myName

// returns -> 'Jun'

 

window.myName ===myName

// returns -> true

 

앞서 global context에서 consloe.log(this) 를 실행함으로써 우리는 this가 global object에서 호출됨을 알았다. 

 

console.log(this)

// returns -> window {...}

 

 

 

이제 함수 내부에 this를 넣어보고자 한다. this의 value는 함수가 어떻게 호출되냐에 따라 결정된다. 

그러면 함수 내부에 this가 있는 함수는 어떻게 return될 것인가 알아보기 위해 아래 코드를 브라우저 콘솔에 입력해보자.

 

function test () {

return this;

}

test()

 

다시 한번 this는 global(window) object를 return한다. 

여기서 this는 선언된 객체의 내부에 있지 않기 때문에 기본적으로 global(window) object이다. 

 

만약 strict mode에서 위 함수를 실행하면 this는 undefined가 될 것이다. 

 

 

 

 

#2 Declared Object

만약 this가 선언된 객체의 내부에서 사용되면 this의 value는 호출된 method의 closet parent object이다.

아래 코드에서 object 객체를 선언하고 full method 내부에서 this를 사용했다. 

var person = {
  first: 'John',
  last: 'Smith',  
  full: function() {
    console.log(this.first + ' ' + this.last);
  }
};
person.full();
// logs => 'John Smith'

 

this에 대해 좀 더 깊게 알아보기 위해 console.log(this)를 대신 사용하였다.  아래 코드를 복사하여 브라우저 콘솔에서 실행시켜 return값을 확인해보자. 

var person = {
  first: 'John',
  last: 'Smith',  
  full: function() {
    console.log(this);
  }
};
person.full();
// logs => Object {first: "John", last: "Smith", full: function}

 

콘솔에서 person object가 return되고 this가 person의 value로 사용되었음을 확인할 수 있을 것이다.

 

만약 중첩된 objects을 가지고 있다면 어떤 값을 기대할 수 있을까? 아래 예제 코드를 통해 확인해보자. 

우리는 위 코드와 마찬가지로 first, last, full 로 동일한 key값을 가진 person 객체를 가지고 있다. 그리고 중첩된 personTwo object를 가지고 있다. personTwo 역시 동일한 세가지 key값을 가지고 있다. 

var person = {
  first: 'John',
  last: 'Smith',
  full: function() {
    console.log(this.first + ' ' + this.last);
  },
  personTwo: {
    first: 'Allison',
    last: 'Jones',
    full: function() {
      console.log(this.first + ' ' + this.last);
    }
  }
};

 

만약 full method들을 호출한다면 어떤 결과값이 호출될까?

person.full();
// logs => 'John Smith'
person.personTwo.full();
// logs => 'Allison Jones'

 

this의 value는 호출된 method의 closest parent object가 된다. 

person.full() 이 호출되면 내부 함수의 this person object에 bound된다. 반면에, person.personTwo.full()로 내부의 full 함수를 호출하면 this는 personTwo object에 바운드 된다.

 

 

#3 The New Keyword

new가 생성자 함수로 사용된다면 this는 새로 만들어진 object에 bound된다. 

function Car(make, model) {
  this.make = make;
  this.model = model;
};

 

위 예제 코드에서 this가 global object에 bound 되었다.  ( new keyword를 사용하기 전까지는.. )

new를 사용하면 this의 value는 빈 객체가 된다. 아래 예제에서는 myCar가 된다. 

var myCar = new Car('Ford', 'Escape');
console.log(myCar);
// logs => Car {make: "Ford", model: "Escape"}

이것을 이해하기 위해서는 new keyword에 대해 정확히 이해할 필요가 있다. 

new keyword를 확인하면 this는 새로 만들어진 빈 객체임을 기억해라.

 

 

 

#4 Call, Bind, Apply

call, bind, apply를 사용하여 this의 value 값을 좀 더 명확하게 할 수 있다. 

이 세가지는 유사하지만 사소한 차이를 이해하는 것이 중요하다. 

call 과 apply는 즉시 호출한다. Call은 parameter의 숫자를 this 로 한다. 

apply는 오직 2가지의 parameter만 가지는데 this와 더해지는 argument들의 배열이 그것들이다. 

 

아래 예제코드를 통해 좀 더 확실히 이해해보도록 하자. 우리는 숫자들을 add할 것이다. 

아래 코드를 복사하여 브라우저콘솔에 실행하고 함수를 호출해보자.

function add(c, d) {
  console.log(this.a + this.b + c + d);
}
add(3,4);
// logs => NaN

 

add 함수는 NaN을 기록한다. 이는 this.a와 this.b가 undefined이기 때문이다. 이 두 변수들은 존재하지 않는다. 그리고 undefined인 변수에 숫자를 add할 수 없다. 

 

우리는 객체와 함수를 호출하기 위해 call(0과 apply() 를 사용할 수 있다. 

function add(c, d) {
  console.log(this.a + this.b + c + d);
}
var ten = {a: 1, b: 2};
add.call(ten, 3, 4);
// logs => 10
add.apply(ten, [3,4]);
// logs => 10

 

우리가 add.call()을 사용할 때 첫번째 인자는 this로 bound 된다. 

그 다음 parameter들은 우리가 호출하는 함수 내부로 들어가게 된다. 

따라서, add() 에서 this.a는 ten.a가 되고, this.b는 ten.b가 된다. 그리고 우리는 1+2+3+4 또는 10을 return값으로 받는다. 

 

add.apply() 도 유사하다. 첫번째 parameter는 this에 bound된다. 

그리고 그 다음 parameter는 argument들의 배열로 함수에서 사용된다. 

 

Bind는 어떻게 될까? bind() 의 parameter들은 call() 과 동일하지만 bind()는 즉시 호출되지 않는다. 대신 bind() 는 이미 bound 된 this의 context와 함께 함수를 return한다. 이런 점 때문에 bind()는 우리가 모든 argument들을 알지 못할 때 유용하게 사용된다. 

이해를 돕기위해 다시 다음 예제를 확인해보자. 

var small = {
  a: 1,
  go: function(b,c,d){
    console.log(this.a+b+c+d);
  }
}
var large = {
  a: 100
}

콘솔에 위 코드를 입력한 후, 아래 코드를 호출해보자. 

small.go(2,3,4);
// logs 1+2+3+4 => 10

 

그러나 만약 우리가 large.a의 value를 대신 사용하고 싶다면? call/apply를 사용하면 된다. 

small.go.call(large,2,3,4);
// logs 100+2+3+4 => 109

 

만약 우리가 3 argument들을 모두 알지 못한다면? bind를 사용하면 된다. 

var bindTest = small.go.bind(large,2);

 

console.log를 통해 위의 변수 bindTest를 호출하면 우리는 아래와 같은 결과값을 확인할 수 있다. 

console.log(bindTest);
// logs => function (b,c,d){console.log(this.a+b+c+d);}

 

 

bind는 this가 bound 된 함수를 return한다는 것을 기억해라. 

this 는 large object에 성공적으로 bound 된다.  그리고 두번째 argument로는 이미 숫자 2가 할당되어 있다. 

이후 나머지 argument들을 알게되면 우리는 그것들을 추가적으로 할당할 수 있다. 

bindTest(3,4);
// logs 100+2+3+4 => 109

 

위에서의 설명들을 다시 한번 확인하기 위해 위에서 배운 코드들을 모두 사용하여 하나의 block 내부에 작성하였다. 콘솔에 확인해봄으로써 결과값을 확인해보자. 

var small = {
  a: 1,
  go: function(b,c,d){
    console.log(this.a+b+c+d);
  }
}
var large = {
  a: 100
}
small.go(2,3,4);
// logs 1+2+3+4 => 10
var bindTest = small.go.bind(large,2);
console.log(bindTest);
// logs => function (b,c,d){console.log(this.a+b+c+d);}
bindTest(3,4);
// logs 100+2+3+4 => 109

 

 

 

#5 Arrow Function

화살표 함수에 대해서는 추후에 따로 공부할 것이다. 

 

 

 

Conclusion

이제 대부분의 상황에서 this에 무엇이 들어가게 되는지 추론할 수 있을 것이다. 

넘어가기 전에 다음 몇가지를 반드시 기억해라.

 

  • this의 value는 대부분 함수의 실행 컨텍스트에 의해 결정된다.
  • global 스코프에서 this는 global object이다. ( window 객체)
  • 생성자 함수 new가 사용되면 this에 새로 만들어진 객체가 bound된다. 
  • 우리는 call(), bind(), apply()를 통해 this의 value를 설정할 수 있다. 
  • 화살표 함수는 this를 bind하지 않는다. 대신 this는 사전적으로 bound 된다. ( 원래 context에 기반하여 )

 

Comments