본문 바로가기
Archive

call/apply 와 데코레이터, 포워딩

by livemehere 2022. 9. 1.

자바스크립트의 함수는 유연성이 높아, 함수를 이곳저곳 전달하고, 객체로도 사용된다.

그래서 함수의 호출을 포워딩(forwarding), 데코레이팅(decorating)을 할 수 있다.

 

용어를 정리하자면 함수의 행동을 변경시켜주는 함수를 데코레이터라고한다.

아래 코드는 함수의 결과값을 캐싱해서, 이미 했던 연산이라면 캐싱된 값을 반환하도록 하는 데코레이터이다.

이 데코레이터 함수는 어떤 함수든지 그 결과값을 캐싱하도록 해주는 데코레이터이다.

function slow(x){
    console.log(`${x} called!`)
}

function cachingDecorator(func){
    let cache = new Map();

    return function (x){
        if(cache.has(x)){
            return cache.get(x);
        }

        let result = func(x);

        cache.set(x,result);
        return result;
    }
}

slow = cachingDecorator(slow);
slow(1)
slow(2)
slow(1)

이 함수가 반환하는것은 캐싱래퍼 라고한다.

함수가 리턴하는 function(x){} 는 호출 결과를 캐싱하는 로직으로 감싼다(wrapping)

 

직접 해보면서 그렇게 명확히 캐싱래퍼라는 용어는 예시에서 나온건가싶지만, 데코레이터의 역할은 명확하게 알게되었다.

nestjs에서는 어노테이션을이용해서 데코레이터를 지원한다.

 

function.call 로 컨텍스트 저장하기

아래 코드는 this의 컨텍스트를 찾을 수 없기 때문에, undefined가 반환된다.

let obj ={
    name:'kong',
    say(){
        return this.name;
    }
}


function makeNice(func){
    console.log('very nice function called');
    return func() // undefined
}

console.log(makeNice(obj.say))

 

이렇게 내부적으로 this를 참조하고 있는 함수가 전달되면서 컨텍스트를 잃는 상황이 발생한다.

그럴때 앞서말했던것 처럼 자바스크립트의 함수의 유연성을 활용하여 function.call(context,arg1,arg2,...) this를 특정 객체로 지정할 수 있다.

let obj ={
    name:'kong',
    say(){
        return this.name;
    }
}


function makeNice(func){
    console.log('very nice function called');
    return func.call(obj) // kong
}

console.log(makeNice(obj.say))

 

이런식으로 메서드를 만들지않고, 함수를 만들어 컨텍스트를 연결시켜주는 유연함을 발휘할 수 있다.

function sayHi() {
  alert(this.name);
}

let user = { name: "John" };
let admin = { name: "Admin" };

// call을 사용해 원하는 객체가 'this'가 되도록 합니다.
sayHi.call( user ); // this = John
sayHi.call( admin ); // this = Admin

call, apply

call과 유사하게동작하는 함수가있는데, apply이다.

차이점은, 이렇게 context를 전달하면서 함수를 실행할 때 인자를 같이전달해줄 수있는데

call은 인수를 따로따로 전달하고,

apply는 인수를 배열로 전달한다는 점에서 차이가있다.

function cc(...nums){
    console.log(this.name + nums)
}

let p = {
    name:'kong'
}

cc.call(p,1,2,3,4,5,5) // kong1,2,3,4,5,5
cc.apply(p,[1,2,3,4,5,5]) // kong1,2,3,4,5,5

 

개인적으로는 첫번째 파라미터만 context로 고정되고 뒤에는 기존함수를 호출하듯이하면되서 call을 선호하지만

자바스크립트 엔진 내부에서는 apply를 최적화한다고 해서, 성능상으로는 apply가 더 빠르다고 한다.

이렇게 context와 인수 전체를 다른 함수에 전달하는것을 콜 포워딩(call forwarding) 이라고한다.

 

함수빌리기

call과 apply를 활용하면 context를 원하는데로 지정 할 수 있기 때문에, 함수를 빌려서 사용할 수 있다.

아래 예시는 어차피 배열이라서 불필요한 동작이지만, 다른 객체에서 특정한 메서드가 필요하다면 이런식으로 활용이 가능하다.

function cc(...nums){
    const j = [].join.call(nums,'+')
   console.log(j)
}

cc(1,2,3,4)

 

데코레이터사용시 함수프로퍼티를 주의하자

데코레이터를 사용할때, 데코레이터를 적용한 함수에서는 본래 함수의 프로퍼티에 접근할 수 없기 때문에 주의해야한다.

이를 해결하려면 Proxy 객체를 사용해야한다.

반응형

'Archive' 카테고리의 다른 글

prototype 과 상속  (0) 2022.09.01
함수 바인딩  (0) 2022.09.01
잘안알려진 함수특성  (0) 2022.08.31
전역 객체  (0) 2022.08.31
렉시컬 환경과 클로저  (0) 2022.08.31