Olga Climova
Olga Climova

Reputation: 461

How "this" reference is transferred in the following function

In the JS manual I have the following example, that is working correctly:

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

  slow(x) {
    alert("Called with " + 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); // теперь сделаем её кеширующей

alert( worker.slow(2) ); // работает
alert( worker.slow(2) ); // работает, не вызывая первоначальную функцию (кешируется)

The question is: how the "this" reference is transferred into cachingDecorator function, if the cachingDecorator is not declared inside of the object, and is called like worker.slow = cachingDecorator(worker.slow)? I talk about this row inside the cachingDecorator: let result = func.call(this, x).

Upvotes: 0

Views: 48

Answers (3)

CollinD
CollinD

Reputation: 7573

Note that the function cachingDecorator returns a function declared like function(x) {. . .}. Any function like this will inherit context when it is invoked as a reference to an object member:

function magicFn() { return this }
const x = { magicFn };
const y = { someKey: 6, magicFn };
x.magicFn(); // === x, because it was invoked as x.magicFn
y.magicFn(); // === y
magicFn(); // === undefined, no `this` object member reference

So when worker.slow = cachingDecorator(worker.slow) is called, the resulting function invokes the original worker.slow using worker.slow.call(this, x); which proxies the incoming this value (in this case, worker).

Upvotes: 1

user12407908
user12407908

Reputation:

The this is not actually in cachingDecorator, but is rather in the anonymous function being returned. So the this value is not set until that function is invoked.

Because that function is assigned to worker.slow, and you're calling it from that object, the this value gets set to the worker object.

The important thing to remember is that this is kind of like a weird function parameter. It just has a keyword for a name and always gets set (except in arrow functions). It gets set based on how the function is invoked, instead of being set like regular parameters via arguments being passed.

Upvotes: 1

Olga Climova
Olga Climova

Reputation: 461

this reference is transferred in the last 2 rows when the decorator is actually used as worker object is before the dot.

Upvotes: 1

Related Questions