개발공부/자바스크립트

[코어 자바스크립트] this② 함수의 메소드 call, apply, bind

jennayeo 2021. 6. 25. 00:47

 

명시적으로 this를 바인딩하는 방법

 

call 메서드

call 메서드는 메서드의 호출 주체인 함수를 즉시 실행하도록 하는 명령이다. 이때 call메서드의 첫 번째 인자를 this로 바인딩하고, 이후의 인자들을 호출할 함수의 매개변수로 한다.

Function.prototype.call(thisArg[, arg1[, arg2[, ...]]])
var func = function(a,b,c) {
    console.log(this, a, b, c);
};
func(1,2,3); // Window{ ... } 1 2 3
func.call({x:1}, 4, 5, 6); // {x: 1} 4 5 6
var obj = {
    a: 1,
    method: function(x, y) {
        console.log(this.a, x, y);
    }
};

obj.method(2,3); // 1 2 3
obj.method.call({a:4}, 5, 6); // 4 5 6

 

apply 메서드

call 메서드와 기능적으로 동일하지만 call은 인수 목록을, apply는 인수 배열 하나를 받는다는 차이가있다.

apply메서드는 두 번째 인자를 배열로 받아 그 배열의 요소들을 호출할 함수의 매개변수로 지정한다.

var func = function (a, b, c) {
    console.log(this, a, b, c); // {x: 1} 4 5 6
};
func.apply({x: 1}, [4, 5, 6]);

var obj = {
    a: 1,
    method: function(x, y) {
        console.log(this.a, x, y); // 4 5 6
    }
};
obj.method.apply({ a: 4 }, [5, 6]);

 

call / apply 메서드의 활용

유사배열객체에 배열 메서드를 적용

🤔

var obj = {
    0: 'a',
    1: 'b',
    2: 'c',
    length: 3
};
Array.prototype.push.call(obj, 'd');
console.log(obj); // {0: "a", 1: "b", 2: "c", 3: "d", length: 4}

var arr = Array.prototype.slice.call(obj);
console.log(arr); // ["a", "b", "c", "d"]

함수를 선언 후 호출할때 함수.call() 또는 함수.apply() 와 같이 사용한다.

var func = function (a, b, c) {
	console.log(this, a, b, c);
   };

func(1,2,3);
func.call({x:1}, 1, 2, 3);
func.apply(6, [1, 2, 3]);

call메서드는 함수와 똑같이 인자를 넣고, apply메서드는 배열로 넣어준다. 그리고 각각 호출의 인자 앞에 오는 {x:1} 과 6은 this를 지정한 것이다.

 

 

call과 apply 메서드를 이용하면 임의의 객체를 this로 지정 가능하다.

 

이제 이 메서드를 어떻게 활용 할 수 있을까?

- 객체에는 배열 메서드를 직접 사용 할 수 없다.

(배열 메서드: pop, push, concat,.... 등)

- 하지만 객체가 배열의 구조와 비슷하다면(=유사배열객체) 배열 메서드를 사용 가능하다.

- 함수 내부에서 접근할 수 있는 arguments객체도 유사배열객체이다.

- 참고: ES6에서는 유사배열객체 또는 순회 가능한 모든 종류의 데이터 타입을 배열로 전환하는 Array.from 메서드를 도입하였다.

 

생성자 내부에서 다른 생성자 호출하기

생성자 내부에 다른 생성자와 공통된 내용이 있을 경우 call또는 apply를 이용해 반복일 줄일 수 있다.

// Person 클래스함수를 Student, Employee 클래스 함수 내부에서 호출하여 인스턴스의 속성을 정의하도록 구현

function Person(name, gender) {
	this.name = name;
    	this.gender = gender;
}

function Student(name, gender, school) {
	Person.call(this, name, gender);
    	this.school = school;
}

function Employee(name, gender, company) {
	Person.apply(this, [name, gender]);
    	this.company = company;
}

var by = new Student('보영', 'female', '단국대');
var jn = new Employee('재난', 'male', '구골');

// 결과
>> Student {name: "보영", gender: "female", school: "단국대"}
>> Employee {name: "재난", gender: "male", company: "구골"}

 

여러 인수를 묶어 하나의 배열로 전달하고 싶을때 apply를 활용할 수 있다.

// min,max값 구하는 코드
var numbers = [10, 20, 3, 16, 45];
var max = min = numbers[0];
numbers.forEach(function(number) {
	if (number > max) {
    	max = number;
    }
    if (number < min) {
    	min = number;
    }
});
console.log(max, min);

// apply 사용
var numbers = [10, 20, 3, 16, 45];
var max = Math.max.apply(null, numbers);
var min = Math.min.apply(null, numbers);
// this값은 어떤것이 들어오든 상관없으므로 null
console.log(max, min);

// ES6에서는 스프레드 연산자 사용 가능
const numbers = [10, 20, 3, 16, 45];
const max = Math.max(...numbers);
const min = Math.min(...numbers);
console.log(max, min);

 

bind 메서드

  • ES5에서 추가된 기능
  • call과 비슷하지만 즉시 호출하진않고 넘겨 받은 this 및 인수들을 바탕으로 새로운 함수를 반환하기만하는 메서드
  • 목적1) 함수에 this를 미리 적용
    목적2) 부분 적용 함수 구현

var bindFunc1은 this를 적용시켰고, bindFunc2는 this적용과 부분 적용 함수도 구현하였다.

 

name 프로퍼티

 

상위 컨텍스트의 this를 내부함수나 콜백 함수에 전달하기

메서드의 내부함수에서의 this는 self를 사용하여 우회할 수 있었는데, call, apply, bind 메서드를 이용하여 더 간단하게 처리가능하다.

화살표 함수를 사용할땐 this를 바인딩하지않기때문에 스코프체인상 가장 가까운 this에 접근한다.

따라서, this를 우회하거나 call, apply, bind를 사용할 필요가없다.

 

별도의 인자로 this를 받는 경우(콜백 함수 내에서의 this)

콜백 함수를 인자로 받는 메서드 중 일부는 추가로 this로 지정할 객체를 인자로 지정할 수 있는 경우가 있다.

 

정리

- 전역공간에서의 this는 전역객체 참조
- 메서드로서 호출시 this는 메서드 호출 주체(메서드명 앞의 객체) 참조
- 함수로서 호출시 this는 전역객체 참조
- 콜백 함수 내부에서는 해당 콜백 함수의 제어권을 넘겨받은 함수가 정의한 바에 따르며, 
  정의하지 않은 경우엔 전역객체 참조
- 클래스 함수에서의 this는 생성될 인스턴스 참조
- call, apply 메서드는 this를 명시적으로 지정하면서 함수 또는 메서드 호출
- bind 메서드는 this 및 함수에 넘길 인수를 일부 지정해서 새로운 함수 만듦
- 요소를 순회하면서 콜백함수를 반복 호출하는 내용의 일부 메서드는 별도의 인자로 this를 받기도 한다.

 

 

출처: 정재남, 코어 자바스크립트, 위키북스(2019), 3장 this