본문 바로가기

JavaScript/JavaScript기초

[Javascript] 데코레이터, 포워딩과 call/apply

데코레이터를 이용하여 캐싱 기능 추가

데코레이터란 함수의 인수로 받은 함수의 행동을 변경시켜 주는것을 의미함

 

아래 코드는 데코레이터 함수를 이용하여 특정 함수에 캐싱 기능을 추가

function myFunc(num){
	
    console.log(`${num}을 호출함`);
    return num * num;
} // num을 호출받아서 num * num 의 결과를 리턴해주는 함수

function decoFunc(func){ // 함수의 cache를 생성해주는 데코레이터
	
    let cache = new Map(); //캐시를 저장할 맵 생성
    
    return function(num){ 
    	if(cache.has(num)){ //인수로 받은 num 키가 있을경우
        	
            return cache.get(num); //캐시에서 값을 불러옴
        }else{
        	
            let res = func(num); // 키가 없을경우 num을 인수로 주어 myFunc 결과를 저장
            cache.set(num,res);// num을 키, myFunc의 리턴값을 값으로 캐싱
            return res;// 값을 반환
        }
    }
}

let deco = decoFunc(myFunc);
console.log(deco(1));
console.log(deco(1));
console.log(deco(2));
console.log(deco(2));

 

 

해당 인수로 전해준 값을 처음 호출할때는 캐싱이 되어있지 않아서 myFunc함수 자체가 실행이 되지만 두번째 부터는 캐시에 저장이 되기 때문에 데코레이터 내부의 캐시에서 캐싱되어있는 값만 가져올 수 있음

 

이러한 데코레이터를 사용하면 데코레이터를 재사용 할 수 있고, 캐싱로직을 함수의 로직과 분리하여 복잡성이 줄어든다는 이점이 있음

 

func.call 사용

만약 데코레이터의 인자로 this가 사용되는 객체 메서드를 사용하면 정상적으로 작동되지 않음.

 

decoFunc는 위에 코드를 그대로 사용한다고 가정

let obj = {
	
    someNum(){ return 2; },
    myFunc(num){ return this.someNum() * num; }
}

let deco = decoFunc(obj.myFunc);

console.log(deco(2));

 

decoFunc에 인자로 전해줄 때 myFunc의 this 는 obj가 아니라 undefined이기 때문에 에러가 발생함

 

이러한 문제를 해결하기 위해 func.call 을 사용하여 컨텍스트를 지정해줄 수 있음

 

func.call의 문법은 아래와 같음

func.call(context[,arg1, arg2 ...])
  • context : this로 사용할 컨텍스트
  • arg: 함수의 인자로 전달할 값들(생락가능)

 

func.call 을 사용하여 위의 코드를 수정


let obj = {
	
    someNum(){ return 2; },
    myFunc(num){ return this.someNum() * num; }
}

function decoFunc(func){ 
	
    let cache = new Map();
    
    return function(num){ 
    	if(cache.has(num)){ 
        	
            return cache.get(num); 
        }else{
        	
            let res = func.call(obj,num); // obj를 this로 설정
            cache.set(num,res);
            return res;
        }
    }
}

let deco = decoFunc(obj.myFunc);

console.log(deco(2));

 

컨텍스트로 obj를 추가하여 this가 obj로 설정되므로 값이 제대로 들어간 것을 볼  수 있음

 

func.apply

func.apply 는 func.call 과 같은 기능을 하지만, 함수의 인자를 전달할 때 배열을 이용하여 전달함

func.apply(context,args)

 

같은 함수를 apply와 call을 이용하여 인자를 전달

function addNums(a,b,c){ return a+b+c; }

let call = addNums.call(null,1,2,3) // call 은 인자를 전달하기 위해 1,2,3을 인수로 전달

let apply = addNums.apply(null,[1,2,3]) // apply는 인자의 개수에 맞춰서 하나의 배열로 전달

console.log(call)
console.log(apply)

 

두 변수의 결과가 동일한 것을 확인할 수 있음

 

참조: https://ko.javascript.info/call-apply-decorators