Proxyとは
これらは基本的な言語操作(例えば、プロパティ検索、代入、列挙、関数呼び出しなど)に割り込み、動作をカスタマイズできます。
メタプログラミングより
らしいです。自分の理解で説明すると、「プロパティ値に実際にアクセスする前にプロパティ値を好きに弄れる。元の値も返そうと思えば返せる」というような感じです。
Proxy Handler
new Proxy(obj, handler)のように第2引数に渡します。ハンドラには特定のメソッドをいくつか作る必要があります。例えば、
値の取得時
get値の設定時
setin構文でhas関数実行時
applynewした時constructor
など。そしてこれらの事をトラップ(trap)と言います。
Reflect について
Reflectを使うとgetterやsetterなど関数の中のthisをProxytargetのように扱うことができます。
例
まずはgetとsetだけ見ていきます。
getトラップ
const realObj = {
  foo: 'foo',
  get bar() {
    return this._bar;
  }
};
const handler = {
  get(target, propName, receiver) {
    if (target[propName]) {
      return Reflect.get(...arguments);
    }
    return 'default value';
  },
}
const obj = new Proxy(realObj, handler);
console.log(obj.foo, obj.bar); // 'foo' 'default value'これはrealObjにgetトラップを適用してます。obj.fooの時はそのまま値が返りますが、obj.barの時はthis._barという値がないのでdefault valueが返ります。
setトラップ
まずsetトラップは値を入れたか入れないかでbooleanを返すようにします。  
const realObj = {
  foo: 0,
  _bar: 0,
  set bar(value) {
    this._bar = value;
  },
  set baz(value) {
    this._baz = value;
  }
};
const handler = {
  set(target, propName, value, receiver) {
    if (Object.prototype.hasOwnProperty.call(target, propName)) {
      Reflect.set(...arguments);
      return true;
    }
    return false;
  },
}
const obj = new Proxy(realObj, handler);
obj.foo = obj.bar = obj.baz = 1;
console.log(obj.foo, obj._bar, obj._baz) // 1 1 undefinedこれはfooと_barには1が入りますが、_barは入りません。これはthis._bazが無いためです。