NoHomey / bind-decorator

The fastest automatic method.bind(this) decorator
MIT License
68 stars 11 forks source link

@bound method on parent overwrites child method #12

Open pzuraq opened 5 years ago

pzuraq commented 5 years ago

Currently, if the super class method is marked with @bound, the call to super will then overwrite the subclass's version.

class Counter extends React.Component {
    ...
    @bound
    handleClick() {
        this.setState({ count: this.state.count + 1 })
    }
    ...
}

class SpecialCounter extends Counter {
    handleClick() {
        super.handleClick();
        // do more things
    }
    ...
}

The best strategy we have found to mitigate this is to use a WeakMap to map bound functions to the instance, and to bind the function in a getter:

const BINDINGS_MAP = new WeakMap();

export function bound(desc) {
  let boundFn = desc.descriptor.value;

  desc.descriptor = {
    get() {
      let bindings = BINDINGS_MAP.get(this);

      if (bindings === undefined) {
        bindings = new Map();
        BINDINGS_MAP.set(this, bindings);
      }

      let fn = bindings.get(boundFn);

      if (fn === undefined) {
        fn = boundFn.bind(this);
        bindings.set(boundFn, fn);
      }

      return fn;
    }
  }

  return desc;
}