[TIL] javascript와 this

gun·2021년 3월 13일
1

TIL

목록 보기
15/19

javascript의 this란?

Javascript에서 함수의 this 키워드는 다른 언어와 동작합니다.

자바스크립트에서 모든 함수는 실행될 때마다 함수 내부에 this라는 객체가 추가된다. arguments라는 유사 배열 객체와 함께 함수 내부로 암묵적으로 전달되는 것이다. 그렇기 때문에 자바스크립트에서의 this는 함수가 호출된 상황에 따라 그 모습을 달리한다.

대부분의 경우 javascript의 this의 값은 함수를 호출한 방법에 의해 결정됩니다. 즉 실행중에는 할당으로 설정할 수 없고 함수를 호출할 때 마다 this의 값이 결정 된다는 말 입니다.

아직 잘 이해가 가지 않습니다. 예제를 통해 정확하게 this란 무엇이고 어디서 어떻게 사용되는가에 대해 공부해 보겠습니다.

Javascript this 결정 조건

  1. 함수 호출
  2. 메소드 호출
  3. 생성자 호출
  4. call, apply, bind

1. 함수 호출

기본적으로 this 를 전역에서 호출하게 되면 전역객체인 window에 반인딩 됩니다.
아직 무슨 소린지 이해가 가지 않습니다. 예제를 통해 알아보겠습니다.

console.log(this) // window
alert(this === window) // true

var num = 100;

function add(x){
    let num = 10
    console.log(this.num, num, x)
    console.log(this.num + x)
}

add(3) // 103

이처럼 전역 변수인 num = 100을 선언하고 함수 내에서 this를 사용하게 되면 함수 내부의 num을 불러오는 것이 아니라 전역에 있는 전역에 선언되어 있는 num을 불러오게 됩니다.

2. 메소드 호출

메소드란 무엇인가? 메소드란 객체의 프로퍼티가 함수일 경우 메소드라고 부릅니다. this는 함수를 실행할 때 함수를 소유하고 있는 객체를 참조하게 됩니다. 즉 해당 메서드를 호출한 객체로 바인딩 되게 됩니다.

let obj = {
    name: 'foo',
    sayName: function(){
        console.log(this)
    }
}
obj.sayName() // obj:{name: foo, sayName()}

위 결과처럼 sayName의 결과가 메서드를 호출한 obj를 가르키는 것을 볼 수 있습니다.

또 다른 결과로 메서드 안에서 함수를 호출하게 되면 어떻게 될까요?

 let obj = {
    name: 'foo',
    sayName: function(){
        console.log(this)
    var sayName1 = function(){
        console.log(this)
        }
    sayName1()
    }
}
obj.sayName() // obj={name:foo, sayName:f()}
//Window

이처럼 sayName의 this는 메서드 호출할 때와 결과가 같습니다. 그렇기에 obj가 this로 바인딩 되고 메서드를 호출한 obj가 this에 출력되게 됩니다.
하지만 sayName1의 결과는 window를 가르키고 있습니다. sayName1은 함수로 메서드 안에서 호출하고 있지만 함수 내부의 this는 전역 객체를 참조하게 된다는 규칙 때문에 첫 예제로 본 this의 함수 호출 결과를 따르게 됩니다.

3. 생성자 함수 호출

저희는 함수에서 this를 호출하는 것을 위에서 공부해봤습니다. this는 함수를 호출한 방법에 위해 가르키는 주소가 달라집니다. new키워드를 통해 생성자 함수를 호출 할 때는 또 this가 다르게 바인딩 됩니다.

new 키워드를 통해 함수 호출 과정

  • new키워드를 통해서 호출된 함수 내부에서의 this는 객체 자신이 됩니다.
  • new 연산자를 통해 함수를 호출하게 되면 일단 빈 객체가 생성되고 this가 바인딩 됩니다. 이 객체는 함수를 통해 생성된 객체이며 자신의 부모 프로토 타입 객체와 연결되어 있습니다. 그리고 return 문이 명시되어 있지 않은 경우 this로 바인딩 된 새로 생성한 객체가 리턴 됩니다.
let UserObj = function(name) {
  this.name = name
  console.log(this)
}
let userName = new UserObj("gunwoo"); //UserObj
console.log(userName.name) // gunwoo

위 결과처럼 this는 UserObj자기 자신을 가르키게 됩니다.

call, apply, bind 메소드 호출

위 호출 방법들에 의존하지 않고 this의 주소를 설정할 수 있는 다른 방법이 있습니다. 그 방법은 call, apply, bind 메소드 호출 입니다.

객체 안의 메소드, 함수를 호출하는 경우를 다시 보겠습니다.

let obj = {
    name: 'foo',
    sayName: function(){
        console.log(this)
    var sayName1 = function(firtName, lastName){
        console.log(this.name, firtName, lastName);
        }.bind(this, 'gun', 'woo')	//bind메소드 호출
    sayName1()
    }
}
obj.sayName() // obj={name:foo, sayName:f()}
//foo gun woo
 let obj = {
    name: 'foo',
    sayName: function(){
        console.log(this)
    var sayName1 = function(firtName, lastName){
        console.log(this.name, firtName, lastName);
        }
    sayName1.call(this, 'gun', 'woo')	//call메소드 호출
    }
}
obj.sayName() // obj={name:foo, sayName:f()}
//foo gun woo
 let obj = {
    name: 'foo',
    sayName: function(){
        console.log(this)
    var sayName1 = function(firtName, lastName){
        console.log(this.name, firtName, lastName);
        }
    sayName1.apply(this, ['gun', 'woo'])	//apply메소드 호출
    }
}
obj.sayName() // obj={name:foo, sayName:f()}
//foo gun woo

다음과 같이 분명 sayName1의 this는 함수에서 호출하는 것을 볼 수 있습니다.
하지만 call, apply, bind 메소드를 사용함으로 인해 this.name이 obj.name을 가르키는 것을 볼 수 있습니다.
세 메소드를 자세히 보시면 각각 호출하는 방식과 사용하는 방식의 차이가 있습니다.
bind vs apply, call

bind는 함수를 선언할 때 this와 파라미터를 저정해줄 수 있습니다. 
call과 apply는 함수를 호출할 때 this와 파라미터를 저정해준다.

apply vs bind, call

apply 메소드는 첫번째 인자로 this를 넘겨주고 두번째 인자로 파라미터를 배열로 넘겨주어야 합니다.
bind, call메소드는 파라미터를 하나씩 넘겨주어야 합니다.

마치며....

this의 호출 방법에 대해 공부해 보았습니다. 어떻게 호출 되어 사용해야 하는지는 알겠지만 어디서 어떻게 사용해야 효율적일지 잘 생각이 나지 않습니다. 이 부분은 공부를 한 뒤 다시 블로깅 해야 겠습니다..

0개의 댓글