ES 6-Proxyとデータハイジャック(12)


先端界の空前の繁栄に伴い、Anglar、Vue、Reactなど、様々なmvvmフレームワークの百家争鳴を含む様々なフレームワークが登場し、データバインドを実現することができ、手動でDOM操作を行う必要がなくなり、それらの実現原理も基本的に汚れた検査やデータハイジャックである.私たちはまずVueフレームワークで出発し、その中のデータハイジャックの奥義を探求します.
Vue 2.0のバージョンで使用されたデータハイジャックは、はっきり言ってObjectを通過した.defineProperty()はオブジェクト属性のsetterとgetter操作をハイジャックし、データが変動したときにやりたいことをし、栗を挙げます.
var data = {
    name:'xiaoming'
}

Object.keys(data).forEach(function(key){
    Object.defineProperty(data,key,{
        get:function(){
            console.log('get');
        },
        set:function(){
            console.log('          ');
        }
    })
});
data.name //        “get”
data.name = 'xiaohong' //        "          "

でもObjectよりdefinePropertyのより良い実現方法は?
答えは肯定的で、それは私达の今日の主人公です:Proxy
1、Proxy紹介
Proxyという言葉の本来の意味はエージェントであり,ここではエージェントが何らかの操作をエージェントすることを表すために用いられ,エージェントと訳すことができる.
また、ターゲットオブジェクトの前にブロックを設定し、外部からのアクセスは、このブロックを先に通過しなければならないため、外部からのアクセスをフィルタリングして書き換えるメカニズムを提供することも理解できる.
生活の中で、代理モードのシーンは非常によく見られます.例えば、私たちは今、海外製品(彼女にLVのバッグを買って、前提はあなたが先に彼女がいることです.^^)を買う需要があれば、直接海外で買うのではなく、代理購入仲介機関を探しています.このとき,代理購入が果たす役割はエージェントの役割である.
Proxyコンストラクション関数は、エージェント・モードを簡単に使用できます.
var proxy = new Proxy(target, handler);

Proxyコンストラクション関数には、次の2つのパラメータがあります.
targetはProxyでパッケージされた被エージェントオブジェクト(原生配列、関数、さらには別のエージェントを含む任意のタイプのオブジェクトであってもよい).
handlerは、エージェントtargetのいくつかの操作を宣言するオブジェクトで、その属性は、1つの操作を実行するときにエージェントの動作を定義する関数です.
通俗的に言えば、LVのバッグを購入してもらうにはどうすればいいですか?
まず、どのバッグを見たかを代理購入する必要があります.このデザインはProxyの最初のパラメータtargetです.
次に、例えば海外が国内より20%安い場合は2つ、40%安い場合は4つを購入する戦略を立て、この戦略が2番目のパラメータhandleです.
2、Proxyでの処理方法
Proxyには13種類のデータハイジャックの操作があり、それはかなり強力です.
2.1 getメソッド
getメソッドは、オブジェクトのプロパティ値を取得するときに前処理するメソッドで、2つの一般的なパラメータを受け入れます.
  • target:得られた目標値
  • key:オブジェクトのプロパティ
  • に相当するターゲットのkey値
    handleのgetメソッドをシミュレートするために代理購入することができます.以下のようにします.
    var Bao = {
          name: "LV",
        price:9999,
    };
    var proxyBao = new Proxy(Bao, {
        get: function(target, key) {
            if (target['price']>5000) {
              return '        ,   ';
            } else {
              return '        ,   ';
            }
        }
    });
    proxyBao.price
    //"        ,   "
    

    お客様はLVのバッグを買いたいと思っています.心理的な価格は5000で、購入目標と需要を代理購入に伝えました.代理購入は海外の価格を聞いてみました.このLVのバッグは9999で、お客様の心理的な価格を超えています.
    2.2 setメソッド
    setメソッドは、ある属性の付与操作をブロックするために使用され、4つのパラメータを受け入れることができます.
  • target:ターゲット値.
  • key:ターゲットのKey値.
  • value:変更する値.
  • receiver:変更前の元の値.

  • Personオブジェクトには200以下の整数であるべきage属性があると仮定すると、Proxyを使用してageの属性値が要求に合致することを保証できます.
    let validator = {
      set: function(target, key, value) {
        if (key === 'age') {
          if (!Number.isInteger(value)) {
            throw new TypeError('The age is not an integer');
          }
          if (value > 200) {
            throw new RangeError('The age seems invalid');
          }
        }
    
        //         age         ,    
        target[key] = value;
      }
    };
    
    let person = new Proxy({}, validator);
    
    person.age = 100;
    
    person.age // 100
    person.age = 'young' //    The age is not an integer
    person.age = 300     //    The age seems invalid
    

    上記のコードでは、メモリ関数setが設定されているため、要求に合致しないage属性の付与には、データ検証の実装方法であるエラーが投げ出されます.
    3、Proxy比Object.definePropertyのメリット
    3.1サポート配列
    let arr = [1,2,3]
    let proxy = new Proxy(arr, {
        get (target, key, receiver) {
            console.log('get', key)
            return Reflect.get(target, key, receiver)
        },
        set (target, key, value, receiver) {
            console.log('set', key, value)
            return Reflect.set(target, key, value, receiver)
        }
    })
    proxy.push(4)
    //          
    // get push     (   proxy.push   )
    // get length   (      length)
    // set 3 4      (   proxy[3] = 4)
    // set length 4 (   proxy.length = 4)
    

    Proxyは配列のメソッドをリロードする必要がなく,多くのhackを省くことができ,コード量を減らすことはメンテナンスコストを減らすことに等しく,標準は最良である.
    3.2対象
    データハイジャックの問題では、ProxyはObjectと考えられる.defineProperty()のアップグレード版.外部からのオブジェクトへのアクセスは、このブロックを通過する必要があります.したがって、オブジェクト全体のプロパティではなく、オブジェクト全体のプロパティであるため、keysを巡回する必要はありません.
    let obj = {
      name: 'Eason',
      age: 30
    }
    let handler = {
      get (target, key, receiver) {
        console.log('get', key)
        return Reflect.get(target, key, receiver)
      },
      set (target, key, value, receiver) {
        console.log('set', key, value)
        return Reflect.set(target, key, value, receiver)
      }
    }
    let proxy = new Proxy(obj, handler)
    proxy.name = 'Zoe' // set name Zoe
    proxy.age = 18 // set age 18

    3.3ネストサポート
    本質的にProxyもネストをサポートしていない点とObject.defineProperty()は同じです.そのため、従来の解決を段階的に解決する必要がある.Proxyの書き方はgetでProxyを再帰的に呼び出して返します.コードは以下の通りです.
    let obj = {
      info: {
        name: 'eason',
        blogs: ['webpack', 'babel', 'cache']
      }
    }
    let handler = {
      get (target, key, receiver) {
        console.log('get', key)
        //        
        if (typeof target[key] === 'object' && target[key] !== null) {
          return new Proxy(target[key], handler)
        }
        return Reflect.get(target, key, receiver)
      },
      set (target, key, value, receiver) {
        console.log('set', key, value)
        return Reflect.set(target, key, value, receiver)
      }
    }
    let proxy = new Proxy(obj, handler)
    //           set
    proxy.info.name = 'Zoe'
    proxy.info.blogs.push('proxy')
    

    4、適用例
    4.1 Proxyによるフォーム検証
    let person = {
        name: 'xiaoming',
        age: 30
    }
    let handler = {
        set (target, key, value, receiver) {
          if (key === 'name' && typeof value !== 'string') {
            throw new Error('            ')
          }
          if (key === 'age' && typeof value !== 'number') {
            throw new Error('           ')
          }
          return Reflect.set(target, key, value, receiver)
        }
    }
    let boy = new Proxy(person, handler)
    boy.name = 'xiaohong' // OK
    boy.age = '18' //                
    

    5、まとめ
    Proxyは本質的にメタプログラミング非破壊データハイジャックに属し、元のオブジェクトに基づいて機能の派生を行い、元のオブジェクトに影響を与えず、松結合高集約の設計理念に合致している.
    一般的には、Proxyはデータの外側にシェルを取り付け、このシェルを通じて内部のデータにアクセスします.次の図のようにします.
    ProxyはJS開発者にエージェントモデルを使いやすくし、関数をより強くし、ビジネスロジックをより明確にします.
    ProxyはObjectの代わりになるだけでなくdefinePropertyは、非常に多くの機能を拡張しています.Proxyテクノロジーは配列を監視するpushなどの方法操作をサポートし,オブジェクト属性の動的追加と削除をサポートし,応答化されたコード量を極めて簡素化する.Vue 3.0の場合もProxyを使用してコアコードの一部を実装します.
    ビジネス開発ではProxyがシーンを使用することに注意し、オブジェクトの機能が複雑になったり、アクセス制限が必要になったりした場合、エージェントの使用を考慮することができます.