Reputation: 4062
I'm having a difficult problem with decorating an instance method in ES6. I'm having no problem decorating the method, but it seems as though it is stuck with a single state of the instance of the class. Here is what I'm dealing with specifically:
class Test {
init() {
this.foo = 'bar';
}
@decorator
decoratedMethod() {
console.log(this.foo); // undefined
}
}
let test = new Test();
test.init();
test.decoratedMethod();
function decorator(target, name, descriptor) {
let fn = target[ name ].bind(target, 'a', 'b');
return fn;
}
I realize that the code above is doing exactly what it should be, but if I want to have access to foo
and other properties added to the scope how can I decorate decoratedMethod
and still bind new function properties?
Upvotes: 2
Views: 949
Reputation: 161457
Method decorators run once at class declaration time, not when the class is instantiated. That means the target
in your example is Test.prototype
, not an instance. So your example is essentially:
class Test {
init() {
this.foo = 'bar';
}
decoratedMethod() {
console.log(this.foo); // undefined
}
}
Test.prototype.decoratedMethod =
Test.prototype.decoratedMethod.bind(Test.prototype, 'a', 'b');
That should make it clear why your code is failing. The object you are binding has no foo
property, only the instance does.
If you want your decorator to be processed for each instance, things get more complicated and you'd need to make the bind happen after the instance is created. One approach to that would be
function decorator(target, name, descriptor){
const {value} = descriptor;
delete descriptor.value;
delete descriptor.writable;
descriptor.get = function(){
// Create an instance of the bound function for the instance.
// And set an instance property to override the property
// from the object prototype.
Object.defineProperty(this, name, {
enumerable: descriptor.enumerable,
configurable: descriptor.configurable,
value: value.bind(this, 'a', 'b'),
});
return this[name];
};
}
Upvotes: 4