본문 바로가기

Frontend/JAVASCRIPT

[Jacascript] call, apply, bind and this

반응형

이번 포스팅은 this의 4가지 바인딩 말미에서 언급한 강제로 this 바인딩을 변경하는것에 대한 포스팅이다.

this가 가리키는것을 알아야 이번 포스팅을 이해할수 있으니 이 부분을 꼭 알고 와야 한다.

[Javasvript] this는 가리킬뿐, this의 4가지 바인딩
this는 가리킬뿐. this는 객체 생성시, 함수 생성시 자동으로 생성되는 변수같은 놈이다.(그렇다고 변수는 또 아니다...) this는 객체를 "가리킬"뿐이다. (자.동.으로) [Javascript] 값을 저장하는 방식, pass by..
artdev.tistory.com

call, apply, bind 메소드는 Function 객체의 메소드로 , 이 부분을 먼져 알아야 한다. (mdn문서를 보고오면 좋다.)

Function
Function 생성자는 새 Function 객체를 만듭니다.
developer.mozilla.org

또한 Function 객체는 자신만의 property와 method가 없고 Function.prototype객체에서 만들어진 메소드를 사용한다.

즉, Function.prototype 이 call, apply, bind 를 가지고 있다.  (물론 이 외에도 여러가지가 있다.)


1. Function.prototype.call()

  • call() 메소드는 주어진 this 값 및 각각 전달된 인수와 함께 함수를 호출합니다. -mdn-

 함수.call( 주어진 this, 전달인자 )  => 함수의 this가 주어진 this가 된다. , 추가적으로 인자도 넘길수가 있다.

function test(){
  console.log(this.name);
}
test();
test.call();
// 결과는 어떻게 될까?

두 가지 모두 this는 전역객체를 가리키고 있다.

1. call의 인자로 obj객체를 주고 있다. test의 this는 무엇을 가리킬까?

function test(){
  console.log('나는 동적으로 this를바꿀수 있지!', this);
}
const obj = {
  printMe : 10
};
test();
test.call(obj);

test함수의 this가 전역객체에서 obj로 바뀐것을 볼수가 있다. 

2. 이번엔 construct function에서 call을 사용하고 있다.

function test(){
  console.log('나는 동적으로 this를바꿀수 있지!', this);
  console.log('내이름은 : ', this.name);
}
function Foo (){
  this.name = 'park';
  test.call(this);
}

test();
const foo = new Foo();

결과는?

동적으로 바인딩을 바꾸어서 함수를 사용할수 있게 하는것이 바로 call 함수인것이다.

추가적으로 인자를 받아서 쓸수도 있다.

function test(args){
  console.log('나는' , this);
  console.log('나는 동적으로 this를바꿀수 있지!', this.name);
  this.step = args;
  console.log('객체 프러퍼티 step 추가됨', this.step);
}
const obj = {
  name : 'lee'
};
function Foo (){
  this.name = 'park';
  test.call(this,5);
}
test.call(obj,10);
const foo = new Foo();

test에서 args로 받아서 바인딩된 this에서 쓸수도 있다. (여기서는 1개만 받았는데 여러개 받아도 된다.)

// call 함수를 이용하여 Pseudoclassical Subclass Instantiation 을 하는 방법을 소개 하기.

2. Function.prototype.apply()

  • Function.prototype.call() 과 하는 기능은 같다. 다만 추가적으로 인자를 받을때(2번자 인자) 배열로 인자를 받는다. 
const numbers = [5, 6, 2, 3, 7];

const max = Math.max.apply(null, numbers);

console.log(max);
// expected output: 7

const min = Math.min.apply(null, numbers);

console.log(min);
// expected output: 2

apply의 첫번째 인자가 null 인것은 numbers 가 전역에서 만들어져서 임.

Function.prototype.apply()
apply() 메서드는 주어진 this 값과 배열 (또는 유사 배열 객체) 로 제공되는 arguments 로 함수를 호출합니다.
developer.mozilla.org

3. Function.prototype.bind()

bind함수는 앞에서 설명한 call, apply함수와는 약간 다른 성격을 가지고 있다.

call과 apply함수는 동적으로 this를 변경시킬수 있지만 bind는 뜻 그대로 this를 붙잡아버린다.

또한 bind()는 바인딩된 상태가 된다. 함수를 바로 실행시키지 않는다.

const module = {
  x: 42,
  getX: function() {
    return this.x;
  }
}

console.log(module.getX());
// expected output: 42

const unboundGetX = module.getX;
console.log(unboundGetX()); // 전역에서 함수호출
// expected output: undefined

const boundGetX = unboundGetX.bind(module); // module 객체로 바인딩 고정, 
console.log(boundGetX()); // 전역에서 함수호출
// expected output: 42

unboundGetX는 전역스코프에서 module.getX 의 함수만 할받은상태다 즉, 이 상태에서의 this.x 는 undefined.

unboundGetX는 unboundGetX.bind(module) 으로 전역스코프에서 bind를 module로 고정한다.

this가 가리키는것이 module 객체로 고정되었기 때문에 전역에서 함수를 호출해도 값이 출력이 된다.

 

bind 함수는 비동기함수를 실행시킬때 this 바인딩이 풀리는경우 this를 고정시키기 위해 자주 사용된다.

const obj = {
  foo : function(){
      console.log(this)
  }
}
obj.foo(); // obj 를 찍을것이다.
setTimeout(obj.foo,1000); // obj를 찍을까?

setTimeout함수(비동기함수)에 callback으로 준 함수의 this가 window 객체를 가리키고 있다.

비동기 함수의 작동방식에 의해 this가 변해버린것이다. (비동기 함수의 작동방식은 나중에 포스팅할것임)

이 부분을 모르면 함수를 잘 작성했더라도 제대도 작동할수가 없게 되니 주의해야 한다.

1초 후에도 해당객체를 출력하고 싶으면 bind()를 사용하여 this가 가리키는것을 고정(bind)시켜야 한다.

const obj = {
  foo : function(){
      console.log(this)
  }
}
obj.foo();
setTimeout(obj.foo.bind(obj),1000);

의도한대로 잘 찍히는것을 볼수가 있다.

 

반응형