Reputation: 461
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
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
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
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