함수 호출 방식과 this 바인딩

정재성·2022년 8월 10일
0
post-thumbnail

this 바인딩

this 바인딩 ( this 에 바인딩 될 값)은 함수 호출 방식 ,
즉 함수가 어떻게 호출되었는지에 따라 동적으로 결정 된다.

동일한 함수도 다양한 방식으로 호출 할 수 있다.

  • 일반 함수 호출

  • 메서드 호출

  • 생성자 함수 호출

  • function.prototype.apply/call/blind 메서드에 의한 간접 호출

const foo = function () {
  console.dir(this);
};

///1. 일반함수 호출
///this 는 전역 객체 window 를 가리킨다.

foo() ///window

///2.메서드에 호출
///foo함수를 프로퍼티 값으로 할당하여 호출
///foo함수 내부의 this 는 메서드를 호출한 obj 를 가리킨다

const obj = {foo};
obj.foo() //obj

///3.생성자 함수 호출
//foo함수를 new연산자와 함계 생성자 함수로 호출
//foo함수 내부의 this는 생성자 함수가 생성한 인스턴스를 가리킨다.

new foo() //foo {}

1. 일반 함수 호출

기본적으로 this 에는 전역객체가 바인딩 된다.

위 예제처럼 전역 함수는 물론이고 중첩함수를 일반 함수로 호출하면 함수 내부의 this에는 전역객체가 바인딩된다. 다만 this는 객체의 프로퍼티나 메서드를 참조하기 위한 자기 참조 변수 이므로 , 일반 함수에서 this는 의미가 없다.

'strict mode'가 적용된 일반 함수 내부의 this에는 undefined가 바인딩 된다.

메서드 내에서 정의한 중첩함수도 일반 함수로 호출되면 중첩 함수 내부의
this에는 전역객체가 바인딩 된다.

//전역객체 프로퍼티
var value = 1;

const obj = {
  value : 100
  
  foo() {
  console.log("foo's this:" , this) 
    // {value :100 , foo:f}
  console.log("foo's this.value ,this.value)
              //100
              
              //메서드 내에서 정의한 중첩함수.
  function bar() {
  	console.log("bar's this:",this)
    //window
    console.log("bar's this.value:",this.value)
    //1
    }
  bar()
   }
  }
  obj.foo()

이 외에도 콜백 함수가 일반 함수로 호출된다면 콜백 함수 내부의 this에도 전역객체가 바인딩 된다. 어떠한 함수라도 일반함수로 호출 되면 this에 전역객체가 바인딩 된다.

이처럼 일반 함수로 호출된 모든 함수(중첩함수 , 콜백함수 포함 ) 내부의 this는 전역객체가 바인딩 된다.

콜백 함수의 this 바인딩을 메서드의 this바인딩과 일치 시키기 위한 방법은 다음과 같다.

var value = 1;

const obj = {
  value : 100,
  foo() {
    ///this 바인딩 (this) 변수 that에 할당한다.
    const that = this;
    
    //콜백함수 내부에서 this 대신 that을 참조한다.
    
    setTimeout(function () {
      console.log(that.value); ///100
    } , 100)
  }
}
obj.foo()

    

이 방법 외에도 화살표 함수를 이용하는 방법 ,apply() ,call() , bind()를 이용하는 방법으로도 this바인딩을 일치 시킬수 있다.


var value = 1;
const obj = {
  value:100,
  foo() {
    //화살표 함수 내부의 this 는 상위 스코프의 this를 가리킨다.
    setTimeout(() => console.log(this.value) , 100) //100 
  }
};

obj.foo();
  

2. 메서드 호출

메서드 내부의 this에는 메서드를 호출한 객체 , 즉 메서드를 호출할때 메서드 이름 앞의 마침표(.)연산자 앞에 기술한 객체가 바인딩 된다.

const person = {
  name : 'Lee',
  
  getName(){
    ///메서드 내부의 this는 메서드를 호출한 객체에 바인딩 된다
    return this.name;
  }
};

//메서드 getName을 호출한 객체는 person 이다.

console.log(person.getName()); //Lee

getName메서드는 다른객체의 프로처티에 할당하는 것으로 다른 객체의 메서드가 될 수도 있고 일반 변수에 할당하여 일반 함수로 호출될 수도 있다.

const anotherPerson ={
  name:"kim"
};
//getName 메서드를  anotherPerson 객체의 메서드로 할당
anotherPerson.getName = person.getName;

//getName 메서드를 호출한 객체는 anotherPerson이다
console.log(anotherPerson.getName()); //kim
//getName 메서드를 변수에 할당
const getName = person.getName;
//getName메서드를 일반 함수로 호출
console.log(getName());// ''
//일반 함수로 호출된 getName 함수 내부의 this.name은 브라우저 환경에서 window.name과 같다.

따라서 메서드 내부에서 사용된 this는 프로퍼티로 메서드를 가리키고 있는 객체와는 관계가 없고 메서드를 호출한 객체에 바인딩 된다.

즉, this에 바인딩 될 객체는 호출시점에 결정 된다.

생성자 함수 호출

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

생성자 함수는 이름 그대로 객체(인스턴스)를 생성하는 함수이다.
일반 함수와 동일한 방법으로 생성자 함수를 정의하고 new연산자와 함께 호출하면 해당함수는 생성자 함수로 동작한다

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

function Circle(radius) {
  ///생성자 함수 내부의 this는 생성자 함수가 생성할 인스턴스를 가리킨다
  
  this.radius = radius;
  this.getDiameter = function () {
    return 2 * this.redius;
  }
}
///반지름이 5인 Circle 객체를 생성
const circle1 = new Circle(5)
///반지름이 10이 Circle 객체를 생성
const circle2 = new Circlw(10);

console.log(circle1.getDiameter()); //10
console.log(circle2.getDiameter());//20

//new연자와 함꼐 호출하지 않으면 생성자 함수로 동작하지 않는다 즉 일반젇인 함수의 호출이다

const circle3 = Circle(15);

//일반 함수로 호출된 Circle 에는 반환문이 없으므로 암묵적으로 undefined를 반환한다.
console.log(circle3); ///undifined

//일반 함수로 호출된 Circle내부의 this는 전역 객체를 가리킨다.

console.log(radius); //15
profile
기술블로그 / 일상블로그

0개의 댓글