프로그래밍 숲

func.call을 활용해 this undefind 해결하기 본문

프로그래밍_인포/Javascript

func.call을 활용해 this undefind 해결하기

jjscript 2023. 6. 24. 10:31
728x90
반응형

오늘은 지난 시간에 이어서 코어 자바스크립트의 6.9 call/apply와 데코레이터, 포워딩에 대해서 공부해보도록 하겠습니다. 오늘은 'func.call'를 사용해 컨텍스트를 지정하는 것을 중점적으로 다뤄볼 예정입니다.

 

우선 사이트에서 주어진 예시코드는 아래와 같습니다.

// worker.slow에 캐싱 기능을 추가해봅시다.
let worker = {
  someMethod() {
    return 1;
  },

  slow(x) {
    // CPU 집약적인 작업이라 가정
    console.log(`slow(${x})을/를 호출함`);
    return x * this.someMethod(); // (*)
  },
};

// 이전과 동일한 코드
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;
  };
}

console.log(worker.slow(1)); // 기존 메서드는 잘 동작합니다.

worker.slow = cachingDecorator(worker.slow); // 캐싱 데코레이터 적용

console.log(worker.slow(2)); // 에러 발생!, Error: Cannot read property 'someMethod' of undefined

다른 것들은 지난 시간과 비슷한데, 마지막 콘솔로그 실행 시 에러가 발생한다는 점이 다릅니다. 이러한 에러가 발생하는 이유는 함수가 cachingDecorator로 래핑될 때 this의 값이 변경되기 때문입니다. 

decorating error


일반적으로 JavaScript에서 함수를 호출할 때 this는 호출 시점에 의해 결정됩니다. 원본 worker.slow 메서드를 호출할 때 this는 worker 객체를 참조합니다. 그러나 cachingDecorator 함수는 원본 함수의 동작을 변경하는 새로운 함수를 반환하며, 이 함수는 worker 객체의 메서드가 아니기 때문에 this가 undefined가 됩니다. 이를 this의 컨텍스트가 사라졌기 때문이라고 말합니다.

따라서 worker.slow(2)를 호출할 때 this.someMethod()에서 this는 undefined이므로 Cannot read property 'someMethod' of undefined와 같은 오류가 발생합니다.

 

해결 방법

this를 명시적으로 고정해주는 특별한 내장 함수 메서드 func.call(context, ...args) 사용합니다. 변경된 코드는 다음과 같습니다.

let worker = {
  someMethod() {
    return 1;
  },

  slow(x) {
    console.log(`slow(${x})을/를 호출함`);
    return x * this.someMethod(); // (*)
  },
};

function cachingDecorator(func) {
  let cache = new Map();
  return function (x) {
    if (cache.has(x)) {
      return cache.get(x);
    }
    let result = func.call(this, x); // 이젠 'this'가 제대로 전달됩니다.
    cache.set(x, result);
    return result;
  };
}

worker.slow = cachingDecorator(worker.slow); // 캐싱 데코레이터 적용

console.log(worker.slow(2)); // 제대로 동작합니다.
console.log(worker.slow(2)); // 제대로 동작합니다. 다만, 원본 함수가 호출되지 않고 캐시 된 값이 출력됩니다

에러 없이 발생하는 decoration

이제 에러가 없이 발생하는 모습을 볼 수 있습니다.

728x90
반응형
Comments