call, apply

1. apply
: apply() 메서드는 주어진 this 값과 배열 (또는 유사 배열 객체) 로 제공되는 arguments 로 함수를 호출합니다.
2. call
: call() 메소드는 주어진 this 값 및 각각 전달된 인수와 함께 함수를 호출합니다.

function add(x, y) {
  this.val = x + y;
  console.log(this.val);
}

let obj = {val : 0};

add.apply(obj, [2, 8]); // 10 
add.call(obj, 2, 8); // 10 

apply 응용 )

let arr = [7, 35, 2, 8, 21];
Math.min.apply(null, arr); // 2
// 이 경우, this 값이 의미가 없으므로 null로 넘겨도 됨.

call 응용 )

: 배열 메소드를 유사 배열에 적용시키는 방법
=> 메소드를 먼저 기술하고, 그 뒤에 인스턴스(this 인자)를 넘겨줌으로 해결

let todo = document.querySelectorAll('.todo-list li');
console.log('todo ? ', todo);
// todo ?  NodeList(4) [li.todo-item.done.visible, li.todo-item.visible, li.todo-item.visible, li.todo-item.visible]
// 배열 메소드는 유사배열에 사용할 수 없음.
Array.prototype.filter.call(todo, function(aTodo) {
  return aTodo.classList.contains('done');
}) // [li.todo-item.done.visible]
  • Array.prototype.filter : 프로토타입(원형, original form)으로부터 메소드를 가져옵니다.

bind

call/apply와 다르게,
함수를 바로 실행시키지 않고 this 값이 바인딩된 함수를 리턴합니다.

function add(x, y) {
  this.val = x + y;
  console.log(this.val);
}

let obj = {val : 0};

let boundFn = add.bind(obj, 2, 8);
boundFn(); // 10

bind 응용 - 1

: 특정 함수가 this 값을 바꿔버리는 경우

function Box(w, h) {
  this.width = w;
  this.height = h;

  this.getArea = function() {
    return this.width * this.height;
  }

  this.printArea = function() {
    console.log(this.getArea());
  }
}
let b = new Box(100, 50);
setTimeout(b.printArea.bind(b), 2000);
  • setTimeout의 경우, 인자로 넘기는 함수의 this 값이 기본적으로 window 객체가 바인딩됨.
  • this 값이 window로 들어가지 않도록 명시적으로 this값을 인스턴스 b로 지정해야 함.

bind 응용 - 2

: currying => '인자 여러개를 받는 함수''인자 하나를 받는 함수'로 바꾸는 방법

function template(name, money) {
  return '<h1>' + name + '</h1><span>' + money + '</span>';
}

let tmplSteve = template.bind(null, 'steve');
// tmplSteve 함수의 name 파라미터에는 'steve'라는 값이 이미 바인딩 되어있음
tmplSteve(100) // "<h1>steve</h1><span>100</span>"

let tmplHeaeun = template.bind(null, 'heaeun');
tmplHeaeun(2000) // "<h1>heaeun</h1><span>2000</span>"
tmplHeaeun(3000) // "<h1>heaeun</h1><span>3000</span>"

bind 응용 - 3

let btn = document.querySelector('#btn');

function clickHandler(text) {
  console.log(text);
}

btn.onclick = clickHandler.bind(null, 'hello world');