timqian / my-notes

https://github.com/timqian/my-notes/issues
7 stars 2 forks source link

decorator in ecma262 #25

Open timqian opened 8 years ago

timqian commented 8 years ago

Why I want to learn decorator

Find this project in today's github trending, it is using decorator.

Why decorator

Decorators make it possible to annotate and modify classes and properties at design time. While ES5 object literals support arbitrary expressions in the value position, ES6 classes only support literal functions as values. Decorators restore the ability to run code at design time, while maintaining a declarative syntax. ref

what is decorator

Stage: 1(ref)

Refs:

http://hackll.com/2015/07/24/decorators-in-es7/ https://github.com/wycats/javascript-decorators https://github.com/jayphelps/core-decorators.js

try it online:

babel

timqian commented 6 years ago

HOF: higher order function

function doSomething(name) {
  console.log('Hello, ' + name);
}

function loggingDecorator(wrapped) {
  return function() {
    console.log('Starting');
    const result = wrapped.apply(this, arguments);
    console.log('Finished');
    return result;
  }
}

const wrappedDoSomething = loggingDecorator(doSomething);

doSomething('Graham');
// Hello, Graham
wrappedDoSomething('Graham');
// Starting
// Hello, Graham
// Finished

Decorator enabled doing function composition for class/class member

Decorators are actually nothing more than functions that return another function, and that are called with the appropriate details of the item being decorated. These decorator functions are evaluated once when the program first runs, and the decorated code is replaced with the return value.

Class member decorators

function readonly(target, name, descriptor) {
  descriptor.writable = false;
  return descriptor;
}

class Example {
  a() {}
  @readonly
  b() {}
}

const e = new Example();
e.a = 1;

e.b = 2;
// TypeError: Cannot assign to read only property 'b' of object '#<Example>'
alert(JSON.stringify(e));
// replaces the entire method with a new one that logs the arguments, calls the original method and then logs the output.
function log(target, name, descriptor) {
  const original = descriptor.value;
  if (typeof original === 'function') {
    descriptor.value = function(...args) {
      console.log(`Arguments: ${args}`);
      try {
        const result = original.apply(this, args);
        console.log(`Result: ${result}`);
        return result;
      } catch (e) {
        console.log(`Error: ${e}`);
        throw e;
      }
    }
  }
  return descriptor;
}

class Example {
    @log
    sum(a, b) {
        return a + b;
    }
}

const e = new Example();
e.sum(1, 2);
// Arguments: 1,2
// Result: 3
// arrange our decorator to take some arguments
function log(name) {
  return function decorator(t, n, descriptor) {
    const original = descriptor.value;
    if (typeof original === 'function') {
      descriptor.value = function(...args) {
        console.log(`Arguments for ${name}: ${args}`);
        try {
          const result = original.apply(this, args);
          console.log(`Result from ${name}: ${result}`);
          return result;
        } catch (e) {
          console.log(`Error from ${name}: ${e}`);
          throw e;
        }
      }
    }
    return descriptor;
  };
}

class Example {
  @log('some tag')
  sum(a, b) {
    return a + b;
  }
}

const e = new Example();
e.sum(1, 2);
// Arguments for some tag: 1,2
// Result from some tag: 3

Class decorators

applied to the constructor function

function log(Class) {
  return (...args) => {
    console.log(args);
    return new Class(...args);
  };
}

@log
class Example {
  constructor(name, age) {
  }
}

const e = new Example('Graham', 34);
// [ 'Graham', 34 ]
console.log(e);
// Example {}
// passing parameters to decorator
function log(name) {
  return function decorator(Class) {
    return (...args) => {
      console.log(`Arguments for ${name}: args`);
      return new Class(...args);
    };
  }
}

@log('Demo')
class Example {
  constructor(name, age) {}
}

const e = new Example('Graham', 34);
// Arguments for Demo: args
console.log(e);
// Example {}

Useful decorators

https://github.com/jayphelps/core-decorators