Decorator pattern

What is the decorator pattern? Modifiers were introduced in ES7 and, in plain English, are: execute a method, execute it at compile time, pass in the full class or property of the modifier as an argument, and return a new method, which is executed at run time.

The chestnut:

@addStaticProp
class Test {}function addStaticProp(target) {
    target._name  = 'New Properties';
}

console.log(Test._name); // This will print 'new properties'
Copy the code

What @addStaticProp does is directly modify the class property underneath it and add a new static property. It’s like a factory, where we drop the item we need to work with. We don’t care what’s inside the item, we just add more content to it from the outside. It’s easy to look back at the above statement now.

In fact, other languages already have similar methods, such as Java annotations, which are nothing like our modifiers.

Class uses modifiers:

Add attributes and values freely:

function addCustomProp (key, value) {
    return function (target) {
        target[key] = value
    }
}

@addCustomProp('isShow'.true)
class Test {
}
@addCustomProp('name'.'yixin')
class Test {}console.log(Test.isShow); // true
console.log(Test.name); // yixin
Copy the code

Add instance methods to classes freely:

    function mixins(. list) {
        return function (target) {
            Object.assign(target.prototype, ... list) } }const say = () = > {
        console.log('hello world! ')
    }
    
    @minxins(say)
    class TestClass {}
    
    let p1 = new TestClass();
    p1.say(); // hello world
Copy the code

The modifier here adds a method directly to the class’s prototype, so instantiated objects will have that method.

Method uses a decorator

A modifier applied to a method takes three arguments: 1: the target object to be modified, 2: the name of the property to be modified, and 3: the description object of the property. The object content is as follows:

  1. configurableCan I delete it?
  2. enumerableEnumerable (traversal)
  3. valueAttribute values
  4. writableWhether it can be modified

Let’s drink and change the instance property to read only:

function readonly(target, name, descriptor) {
    descriptor.writable = false
    return descriptor;
}
class Test{
    @readonly
    public name = 'yixin';
}

let p1 = new Test();
p1.name = 'Changed name';
console.log(p1.name); // Failed to modify yixin
Copy the code

And the most commonly used journal decorator, log

function log(target, name, descriptor) { let oFn = descriptor.value; Descriptor. Value = function() {console.log(' method ${name} is executing, arguments: ', arguments); return oFn.apply(null, arguments) } return descriptor; } class Test{@log public add(a, b) {return a + b}} (new Test()).add(1,3); // the method $add is executing with ', [1,3]Copy the code

Multiple modifiers use:

Methods can iterate over multiple modifiers, but because modifiers are executed at compile-time and run time executes the compiled code from the modifiers, when a method has more than one modifier, the method enters the modifier from the outside in and then executes from the inside out.

    function consoleLog(value) {
        return function (target, name, descriptor) {
            console.log(value); }}class Test {
        @consoleLog(1);
        @consoleLog(2);
        say(){}},new Test()).say(); // Even if the top decorator compiles first, the result is still 2 and then 1.
Copy the code

Anti-shake modifier

Anti – shake is the method we use most in development

function debounce(wait) {
  return function(target, name, descriptor) {
    const oFn = descriptor.value
    let timer = null
    descriptor.value = function() {
      clearTimeout(timer);
      timer = setTimeout(() = > {
        oFn.apply(_this, arguments)
      }, wait)
    }
  }
}

class Test {
    @debounce(500)
    search() {
        console.log('Query operation'); }}let p1 = new Test();
p1.search();
p1.search();
p1.search();
p1.search();
Copy the code

Throttle modifier

Throttling is also the method we use most in development

    function throttle(wait) {
      return function(target, name, descriptor) {
        const oFn = descriptor.value
        let timer = null
        descriptor.value = function() {
          if (timer) return
          fn.apply(_this, arguments)
          timer = setTimeout(() = > {
            canRun = null
          }, wait)
        }
      }
    }
    
    class Test {
        @throttle(500)
        search() {
            console.log('Query operation'); }}let p1 = new Test();
    p1.search();
    p1.search();
    p1.search();
    p1.search();
Copy the code