Open wangbinyq opened 7 years ago
class Person {
name() { return `${this.first} ${this.last}` }
}
Object.defineProperty(Person.prototype, 'name', {
value: specifiedFunction,
enumerable: false,
configurable: true,
writable: true
});
with decorator
class Person {
@readonly
name() { return `${this.first} ${this.last}` }
}
let description = {
type: 'method',
initializer: () => specifiedFunction,
enumerable: false,
configurable: true,
writable: true
};
description = readonly(Person.prototype, 'name', description) || description;
defineDecoratedProperty(Person.prototype, 'name', description);
function defineDecoratedProperty(target, { initializer, enumerable, configurable, writable }) {
Object.defineProperty(target, { value: initializer(), enumerable, configurable, writable });
}
a simple decorator that memoizes an accessor
class Person {
@memoize
get name() { return `${this.first} ${this.last}` }
set name(val) {
let [first, last] = val.split(' ');
this.first = first;
this.last = last;
}
}
let memoized = new WeakMap();
function memoize(target, name, descriptor) {
let getter = descriptor.get, setter = descriptor.set;
descriptor.get = function() {
let table = memoizationFor(this);
if (name in table) { return table[name]; }
return table[name] = getter.call(this);
}
descriptor.set = function(val) {
let table = memoizationFor(this);
setter.call(this, val);
table[name] = val;
}
}
function memoizationFor(obj) {
let table = memoized.get(obj);
if (!table) { table = Object.create(null); memoized.set(obj, table); }
return table;
}
The decorator takes the target constructor.
@annotation
class MyClass { }
function annotation(target) {
// Add a property on target
target.annotated = true;
}
Since decorators are expressions, decorators can take additional arguments and act like a factory.
@isTestable(true)
class MyClass { }
function isTestable(value) {
return function decorator(target) {
target.isTestable = value;
}
}
class C {
@enumerable(false)
method() { }
}
function enumerable(value) {
return function (target, key, descriptor) {
descriptor.enumerable = value;
return descriptor;
}
}
Because descriptor decorators operate on targets, they also naturally work on static methods. The only difference is that the first argument to the decorator will be the class itself (the constructor) rather than the prototype, because that is the target of the original Object.defineProperty.
For the same reason, descriptor decorators work on object literals, and pass the object being created to the decorator.
https://github.com/wycats/javascript-decorators