Updating the Decorators Proposal for the Holidays

What are decorators and why should you care?

@addMetadata('name-for-library')class MyClass { constructor(database) {  This.db = database; } @logOutput makeDatabaseCall(param) {  // call database  const results = this.db.call('query');  return results; // this value is automatically logged } @bound methodThatRetainsThis(flagVal) {  // Still knows what this is even when passed as a callback  this.flag = flagVal; }}

What needed to change? If I wrote a decorator, how would I update it?

// decorator 1function addMethod(target) { target.prototype.toString = () => 'addMethod decorator';}// decorator 2function noIWantToAddTheMethod(target) { // This will be overridden target.prototype.toString = () => 'noIWantToAddTheMethod decorator';}@addMethod@noIWantToAddTheMethodclass IncommingConflict {}
function addLogger(descriptor) { const {  kind, // This will be "class"  elements // Array of all class elements } = descriptor; const updatedElements = elements.concat([{  kind: 'field',  placement: 'own',  key: 'logger',  descriptor: {}, // argument to Object.defineProperty  initializer: () => (...args) => console.log('Custom Logger', ...args) }]); return {  kind,  elements: updatedElements,  finisher: () => console.log('The class has been created') }// Create a bound version of the method as a field// This is taken from the proposalfunction bound(elementDescriptor) { let {  kind, // This will be "method"  key,  // Name of the method that this is being used on  descriptor } = elementDescriptor; let {  value // method as it was defined on the class } = descriptor function initializer() {  return value.bind(this); } // Return both the original method and a bound function field that calls the method. // (That way the original method will still exist on the prototype, avoiding // confusing side-effects.) let boundFieldDescriptor = { ...descriptor, value: undefined } return {  ...elementDescriptor,  extras: [   { kind: "field", key, placement: "own", descriptor: boundFieldDescriptor, initializer }  ] }}@addLoggerclass YayDecorators { @bound methodThatRetainsThis(flagVal) {  // Still knows what this is even when passed as a callback  this.flag = flagVal; }}const instance = new YayDecorators();const boundMethod = instance.methodThatRetainsThis;setTimeout(() => boundMethod(true), 1000);

I’m just using decorators. What changes do I need to make?

What’s next?

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
SitePen

SitePen

Modernizing Apps, Tools & Teams | sitepen.com | Twitter: @sitepen