Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

javascript decorators #16

Open
wangbinyq opened this issue Jun 27, 2017 · 5 comments
Open

javascript decorators #16

wangbinyq opened this issue Jun 27, 2017 · 5 comments

Comments

@wangbinyq
Copy link
Owner

https://github.com/wycats/javascript-decorators

@wangbinyq wangbinyq changed the title es decorators javascript decorators Jun 27, 2017
@wangbinyq
Copy link
Owner Author

  • an expression
  • that evaluates to a function
  • that takes the target, name, and decorator descriptor as arguments
  • and optionally returns a decorator descriptor to install on the target object

@wangbinyq
Copy link
Owner Author

decorate class property

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;
}

@wangbinyq
Copy link
Owner Author

decorate class

The decorator takes the target constructor.

@annotation
class MyClass { }

function annotation(target) {
   // Add a property on target
   target.annotated = true;
}

@wangbinyq
Copy link
Owner Author

decorate factory

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;
  }
}

@wangbinyq
Copy link
Owner Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant