[Effective JavaScript] 지정된 수신자 객체로 함수를 호출하기 위해 call 메서드를 사용하자

김범식·2023년 6월 29일
0

Effective JavaScript

목록 보기
6/33
post-thumbnail

Call()이란?


call() 메서드는 함수를 호출하는 방법 중 하나로, 특정 객체에서 함수를 호출하면서 this 값을 설정할 수 있다. call() 메서드는 함수와 함께 사용되며, 함수의 첫번째 인자로 객체를 받는다. 이렇게 하므로써 함수 내부에 this를 지정된 객체로 설정할 수 있다.

functionName.call(thisArg, arg1, arg2, ...);
  • functionName : thisArg에서 호출할 함수의 이름 또는 참조
  • thisArg : 함수 내에서 this로 사용될 객체
  • arg1, arg2... : 호출할 함수에 전달할 인자

call() 메서드를 사용하면 함수를 호출하는 동시에 this 값을 지정한 객체로 설정할 수 있다. 이는 함수를 해당 객체의 메서드로서 호출하는 것과 동일한 효과가 있다.



예시

var person = {
	name : "Alice",
	greet : function(){
		console.log("hello"+this.name);
	}
};

var anotherPerson = {
	name : 'Bob'
};

person.greet() ; // 출력 : hello Alice
person.greet.call(anotherPerson) // 출력 : hello Bob

call() 메서드를 사용해서 person.greet.call(anotherPerson) 처럼 호출할 경우, greet() 함수의 this 값을 anotherPerson객체로 설정한다.

이처럼 call() 메서드는 함수를 호출할 때 this 값을 지정하는데 유용하게 사용될 수 있다. 다형성과 상속등의 개념을 구현할 때 유용하다.



지정된 수신자 객체로 함수를호출하기 위해 call 메서드를 사용하자


간혹 수신자 객체의 프로퍼티는 아니지만 수신자 객체를 특정 객체로 지정해 함수를 호출할 필요가 있을 수도 있다. 즉 A 객체의 프로퍼티함수지만 B객체에서 그 함수를 사용하고 싶을 수 있다는 말이다. 물론 다음과 같이 그 메서드를 해당 객체에 새로운 프로퍼티로써 추가할 수 도 있다.

obj.temporary = f; 
var result = obj.temporary(arg1, arg2, arg3);
delete obj.temporary;

이런 접근 방법은 그다지 좋지 않다. objtemporary객체가 이미 존재할경우 충돌할 수 있다. 게다가 예약어는 추가를 금지하기도 한다. 즉 이렇게 임시적으로 추가하는것은 좋지 못하다.

이때 call() 함수를 사용하게 된다.

f.call(obj,arg1,arg2,arg3);

첫번째 인자로 수신자 객체를 전달하는것 말고는 함수를 직접 호출하는것과 비슷하다. 이처럼 call() 메서드는 삭제, 수정, 오버라이딩된 메서드를 호출하는데 도움이 된다.



hasOwnProperty()

javascript 객체의 메서드로, 객체가 특정 속성을 직접 소유하고 있는지 여부를 확인하는데 사용됩니다.

var person = {
  name: 'Alice',
  age: 25
};

console.log(person.hasOwnProperty('name')); // 출력: true
console.log(person.hasOwnProperty('age')); // 출력: true
console.log(person.hasOwnProperty('gender')); // 출력: false

hasOwnProperty 메서드의 call 메서드를 사용하면 , 해당 딕셔너리 객체내에 저장되어 있지 않은 메서드라도 호출하라 수 있다.


var hasOwnProperty = ().hasOwnProperty // 함수를 변수에 저장
dict.too = 1; //프로퍼티 추가
delete dict.hasOwnProperty; // hasOwnProperty는 객체가 기본적으로 가지고 있는 메서드이다. 근데 삭제함 
hasOwnProperty.call(dict, "foo") // true;
hasOwnProperty.call(dict, "hasOwnProperty") // false;

call() 메서드로 인해 hasOwnProperty 내부에 있는 thisdict으로 바인딩 할 수 있어 hasOwnProperty함수를 그대로 사용할 수 있게 된다.


고차함수 정의

call()은 고차함수를 정의하는데도 유용하다. 고차 함수를 위한 일반적인 코딩 관례 중 함수를 호출하기 위한 수신자 객체를 부가적인 인자로 받는 방법이 있다.

var table={
	entries:[],
	addEntry: function(key,value){
		this.entries.push({key:key,value:value});
	},
	forEach:function(f, thisArg){
		var entries = this.entries;
		for (var i = 0 ;i<entries.length;i++){
			var entry = entries[i];
			f.call(thisArg, entry.key, entry.value); // 외부함수를 가져와서 사용함 
		}
	}
};

이를 이용해 한 테이블의 내용을 다른 테이블로 간편하게 복사할 수 있다.

table1.forEach(table2.addEntry, table2)

call을 통해 f함수 안에있는 this의 바인딩을 명확하게 해준다.


만약 call을 사용하지 않고 그냥 table2.addEntryforEach의 인자로 받는다고 생각해보자

var table={
	entries:[],
	addEntry: function(key,value){
		this.entries.push({key:key,value:value});
	},
	forEach:function(f){
		var entries = this.entries;
		for (var i = 0 ;i<entries.length;i++){
			var entry = entries[i];
			f( entry.key, entry.value, i); // 외부함수를 가져와서 사용함 
		}
	}
};

이렇게 되면 ftable2.addEntry 안에 있는 this전역객체 혹은 undefind 가되어 오류를 발생시킨다.



기억할 점

  • 수신자 객체로 함수를 호출하기 위해 call메서드를 사용하자
  • 주어진 객체에 존재하지 않을지도 모르는 메서드를 호출하기 위해 call 메서드를 사용하자
  • 콜백을 위한 수신자 객체를 함께 받는 고차함수를 정의하기 위해 call 메서드를 사용하자
profile
frontend developer

0개의 댓글