茄子在线看片免费人成视频,午夜福利精品a在线观看,国产高清自产拍在线观看,久久综合久久狠狠综合

    <s id="ddbnn"></s>
  • <sub id="ddbnn"><ol id="ddbnn"></ol></sub>

  • <legend id="ddbnn"></legend><s id="ddbnn"></s>

    詳細(xì)探究ES6之Proxy代理
    來源:易賢網(wǎng) 閱讀:997 次 日期:2016-07-29 14:56:28
    溫馨提示:易賢網(wǎng)小編為您整理了“詳細(xì)探究ES6之Proxy代理”,方便廣大網(wǎng)友查閱!

    ES6中提出了一個(gè)新的特性,就是proxy,用來攔截在一個(gè)對象上的指定操作,這個(gè)功能非常的有用。本文會介紹 Proxy的使用方式及列舉具體實(shí)例解釋 Proxy 的使用場景。

    前言

    在ES6中,Proxy構(gòu)造器是一種可訪問的全局對象,使用它你可以在對象與各種操作對象的行為之間收集有關(guān)請求操作的各種信息,并返回任何你想做的。ES6中的箭頭函數(shù)、數(shù)組解構(gòu)、rest 參數(shù)等特性一經(jīng)實(shí)現(xiàn)就廣為流傳,但類似 Proxy 這樣的特性卻很少見到有開發(fā)者在使用,一方面在于瀏覽器的兼容性,另一方面也在于要想發(fā)揮這些特性的優(yōu)勢需要開發(fā)者深入地理解其使用場景。就我個(gè)人而言是非常喜歡 ES6 的 Proxy,因?yàn)樗屛覀円院啙嵰锥姆绞娇刂屏送獠繉ο蟮脑L問。在下文中,首先我會介紹 Proxy 的使用方式,然后列舉具體實(shí)例解釋 Proxy 的使用場景。

    Proxy,見名知意,其功能非常類似于設(shè)計(jì)模式中的代理模式,該模式常用于三個(gè)方面:

    1.和監(jiān)視外部對對象的訪問

    2.函數(shù)或類的復(fù)雜度

    3.操作前對操作進(jìn)行校驗(yàn)或?qū)λ栀Y源進(jìn)行管理

    在支持 Proxy 的瀏覽器環(huán)境中,Proxy 是一個(gè)全局對象,可以直接使用。Proxy(target, handler) 是一個(gè)構(gòu)造函數(shù),target 是被代理的對象,handlder 是聲明了各類代理操作的對象,最終返回一個(gè)代理對象。外界每次通過代理對象訪問 target 對象的屬性時(shí),就會經(jīng)過 handler 對象,從這個(gè)流程來看,代理對象很類似 middleware(中間件)。那么 Proxy 可以攔截什么操作呢?最常見的就是 get(讀?。et(修改)對象屬性等操作,完整的可攔截操作列表請點(diǎn)擊這里。此外,Proxy 對象還提供了一個(gè) revoke 方法,可以隨時(shí)注銷所有的代理操作。在我們正式介紹 Proxy 之前,建議你對 Reflect 有一定的了解,它也是一個(gè) ES6 新增的全局對象。

    Basic

    const target = { 

      name: 'Billy Bob',

      age: 15

    };

    const handler = { 

      get(target, key, proxy) {

        const today = new Date();

        console.log(`GET request made for ${key} at ${today}`);

        return Reflect.get(target, key, proxy);

      }

    };

    const proxy = new Proxy(target, handler);

    proxy.name;

    // => "GET request made for name at Thu Jul 21 2016 15:26:20 GMT+0800 (CST)"

    // => "Billy Bob"

    在上面的代碼中,我們首先定義了一個(gè)被代理的目標(biāo)對象 target,然后聲明了包含所有代理操作的 handler 對象,接下來使用 Proxy(target, handler) 創(chuàng)建代理對象 proxy,此后所有使用 proxy 對 target 屬性的訪問都會經(jīng)過 handler 的處理。

    1. 抽離校驗(yàn)?zāi)K

    讓我們從一個(gè)簡單的類型校驗(yàn)開始做起,這個(gè)示例演示了如何使用 Proxy 保障數(shù)據(jù)類型的準(zhǔn)確性:

    let numericDataStore = { 

      count: 0,

      amount: 1234,

      total: 14

    };

    numericDataStore = new Proxy(numericDataStore, { 

      set(target, key, value, proxy) {

        if (typeof value !== 'number') {

          throw Error("Properties in numericDataStore can only be numbers");

        }

        return Reflect.set(target, key, value, proxy);

      }

    });

    // 拋出錯(cuò)誤,因?yàn)?"foo" 不是數(shù)值

    numericDataStore.count = "foo";

    // 賦值成功

    numericDataStore.count = 333;

    如果要直接為對象的所有屬性開發(fā)一個(gè)校驗(yàn)器可能很快就會讓代碼結(jié)構(gòu)變得臃腫,使用 Proxy 則可以將校驗(yàn)器從核心邏輯分離出來自成一體:

    function createValidator(target, validator) { 

      return new Proxy(target, {

        _validator: validator,

        set(target, key, value, proxy) {

          if (target.hasOwnProperty(key)) {

            let validator = this._validator[key];

            if (!!validator(value)) {

              return Reflect.set(target, key, value, proxy);

            } else {

              throw Error(`Cannot set ${key} to ${value}. Invalid.`);

            }

          } else {

            throw Error(`${key} is not a valid property`)

          }

        }

      });

    }

    const personValidators = { 

      name(val) {

        return typeof val === 'string';

      },

      age(val) {

        return typeof age === 'number' && age > 18;

      }

    }

    class Person { 

      constructor(name, age) {

        this.name = name;

        this.age = age;

        return createValidator(this, personValidators);

      }

    }

    const bill = new Person('Bill', 25);

    // 以下操作都會報(bào)錯(cuò)

    bill.name = 0; 

    bill.age = 'Bill'; 

    bill.age = 15;

    通過校驗(yàn)器和主邏輯的分離,你可以無限擴(kuò)展 personValidators 校驗(yàn)器的內(nèi)容,而不會對相關(guān)的類或函數(shù)造成直接破壞。更復(fù)雜一點(diǎn),我們還可以使用 Proxy 模擬類型檢查,檢查函數(shù)是否接收了類型和數(shù)量都正確的參數(shù):

    let obj = { 

      pickyMethodOne: function(obj, str, num) { /* ... */ },

      pickyMethodTwo: function(num, obj) { /*... */ }

    };

    const argTypes = { 

      pickyMethodOne: ["object", "string", "number"],

      pickyMethodTwo: ["number", "object"]

    };

    obj = new Proxy(obj, { 

      get: function(target, key, proxy) {

        var value = target[key];

        return function(...args) {

          var checkArgs = argChecker(key, args, argTypes[key]);

          return Reflect.apply(value, target, args);

        };

      }

    });

    function argChecker(name, args, checkers) { 

      for (var idx = 0; idx < args.length; idx++) {

        var arg = args[idx];

        var type = checkers[idx];

        if (!arg || typeof arg !== type) {

          console.warn(`You are incorrectly implementing the signature of ${name}. Check param ${idx + 1}`);

        }

      }

    }

    obj.pickyMethodOne(); 

    // > You are incorrectly implementing the signature of pickyMethodOne. Check param 1

    // > You are incorrectly implementing the signature of pickyMethodOne. Check param 2

    // > You are incorrectly implementing the signature of pickyMethodOne. Check param 3

    obj.pickyMethodTwo("wopdopadoo", {}); 

    // > You are incorrectly implementing the signature of pickyMethodTwo. Check param 1

    // No warnings logged

    obj.pickyMethodOne({}, "a little string", 123); 

    obj.pickyMethodOne(123, {});

    2. 私有屬性

    在 JavaScript 或其他語言中,大家會約定俗成地在變量名之前添加下劃線 _ 來表明這是一個(gè)私有屬性(并不是真正的私有),但我們無法保證真的沒人會去訪問或修改它。在下面的代碼中,我們聲明了一個(gè)私有的 apiKey,便于 api 這個(gè)對象內(nèi)部的方法調(diào)用,但不希望從外部也能夠訪問 api._apiKey:

    var api = { 

      _apiKey: '123abc456def',

      /* mock methods that use this._apiKey */

      getUsers: function(){}, 

      getUser: function(userId){}, 

      setUser: function(userId, config){}

    };

    // logs '123abc456def';

    console.log("An apiKey we want to keep private", api._apiKey);

    // get and mutate _apiKeys as desired

    var apiKey = api._apiKey; 

    api._apiKey = '987654321';

    很顯然,約定俗成是沒有束縛力的。使用 ES6 Proxy 我們就可以實(shí)現(xiàn)真實(shí)的私有變量了,下面針對不同的讀取方式演示兩個(gè)不同的私有化方法。

    第一種方法是使用 set / get 攔截讀寫請求并返回 undefined:

    let api = { 

      _apiKey: '123abc456def',

      getUsers: function(){ }, 

      getUser: function(userId){ }, 

      setUser: function(userId, config){ }

    };

    const RESTRICTED = ['_apiKey'];

    api = new Proxy(api, { 

      get(target, key, proxy) {

        if(RESTRICTED.indexOf(key) > -1) {

          throw Error(`${key} is restricted. Please see api documentation for further info.`);

        }

        return Reflect.get(target, key, proxy);

      },

      set(target, key, value, proxy) {

        if(RESTRICTED.indexOf(key) > -1) {

          throw Error(`${key} is restricted. Please see api documentation for further info.`);

        }

        return Reflect.get(target, key, value, proxy);

      }

    });

    // 以下操作都會拋出錯(cuò)誤

    console.log(api._apiKey);

    api._apiKey = '987654321';

    第二種方法是使用 has 攔截 in 操作:

    var api = { 

      _apiKey: '123abc456def',

      getUsers: function(){ }, 

      getUser: function(userId){ }, 

      setUser: function(userId, config){ }

    };

    const RESTRICTED = ['_apiKey'];

    api = new Proxy(api, { 

      has(target, key) {

        return (RESTRICTED.indexOf(key) > -1) ?

          false :

          Reflect.has(target, key);

      }

    });

    // these log false, and `for in` iterators will ignore _apiKey

    console.log("_apiKey" in api);

    for (var key in api) { 

      if (api.hasOwnProperty(key) && key === "_apiKey") {

        console.log("This will never be logged because the proxy obscures _apiKey...")

      }

    }

    3. 訪問日志

    對于那些調(diào)用頻繁、運(yùn)行緩慢或占用執(zhí)行環(huán)境資源較多的屬性或接口,開發(fā)者會希望記錄它們的使用情況或性能表現(xiàn),這個(gè)時(shí)候就可以使用 Proxy 充當(dāng)中間件的角色,輕而易舉實(shí)現(xiàn)日志功能:

    let api = { 

      _apiKey: '123abc456def',

      getUsers: function() { /* ... */ },

      getUser: function(userId) { /* ... */ },

      setUser: function(userId, config) { /* ... */ }

    };

    function logMethodAsync(timestamp, method) { 

      setTimeout(function() {

        console.log(`${timestamp} - Logging ${method} request asynchronously.`);

      }, 0)

    }

    api = new Proxy(api, { 

      get: function(target, key, proxy) {

        var value = target[key];

        return function(...arguments) {

          logMethodAsync(new Date(), key);

          return Reflect.apply(value, target, arguments);

        };

      }

    });

    api.getUsers();

    4. 預(yù)警和攔截

    假設(shè)你不想讓其他開發(fā)者刪除 noDelete 屬性,還想讓調(diào)用 oldMethod 的開發(fā)者了解到這個(gè)方法已經(jīng)被廢棄了,或者告訴開發(fā)者不要修改 doNotChange 屬性,那么就可以使用 Proxy 來實(shí)現(xiàn):

    let dataStore = { 

      noDelete: 1235,

      oldMethod: function() {/*...*/ },

      doNotChange: "tried and true"

    };

    const NODELETE = ['noDelete']; 

    const NOCHANGE = ['doNotChange'];

    const DEPRECATED = ['oldMethod']; 

    dataStore = new Proxy(dataStore, { 

      set(target, key, value, proxy) {

        if (NOCHANGE.includes(key)) {

          throw Error(`Error! ${key} is immutable.`);

        }

        return Reflect.set(target, key, value, proxy);

      },

      deleteProperty(target, key) {

        if (NODELETE.includes(key)) {

          throw Error(`Error! ${key} cannot be deleted.`);

        }

        return Reflect.deleteProperty(target, key);

      },

      get(target, key, proxy) {

        if (DEPRECATED.includes(key)) {

          console.warn(`Warning! ${key} is deprecated.`);

        }

        var val = target[key];

        return typeof val === 'function' ?

          function(...args) {

            Reflect.apply(target[key], target, args);

          } :

          val;

      }

    });

    // these will throw errors or log warnings, respectively

    dataStore.doNotChange = "foo"; 

    delete dataStore.noDelete; 

    dataStore.oldMethod();

    5. 過濾操作

    某些操作會非常占用資源,比如傳輸大文件,這個(gè)時(shí)候如果文件已經(jīng)在分塊發(fā)送了,就不需要在對新的請求作出相應(yīng)(非絕對),這個(gè)時(shí)候就可以使用 Proxy 對當(dāng)請求進(jìn)行特征檢測,并根據(jù)特征過濾出哪些是不需要響應(yīng)的,哪些是需要響應(yīng)的。下面的代碼簡單演示了過濾特征的方式,并不是完整代碼,相信大家會理解其中的妙處:

    let obj = { 

      getGiantFile: function(fileId) {/*...*/ }

    };

    obj = new Proxy(obj, { 

      get(target, key, proxy) {

        return function(...args) {

          const id = args[0];

          let isEnroute = checkEnroute(id);

          let isDownloading = checkStatus(id);   

          let cached = getCached(id);

          if (isEnroute || isDownloading) {

            return false;

          }

          if (cached) {

            return cached;

          }

          return Reflect.apply(target[key], target, args);

        }

      }

    });

    6. 中斷代理

    Proxy 支持隨時(shí)取消對 target 的代理,這一操作常用于完全封閉對數(shù)據(jù)或接口的訪問。在下面的示例中,我們使用了 Proxy.revocable 方法創(chuàng)建了可撤銷代理的代理對象:

    let sensitiveData = { username: 'devbryce' };

    const {sensitiveData, revokeAccess} = Proxy.revocable(sensitiveData, handler);

    function handleSuspectedHack(){ 

      revokeAccess();

    }

    // logs 'devbryce'

    console.log(sensitiveData.username);

    handleSuspectedHack();

    // TypeError: Revoked

    console.log(sensitiveData.username);

    Decorator

    ES7 中實(shí)現(xiàn)的 Decorator,相當(dāng)于設(shè)計(jì)模式中的裝飾器模式。如果簡單地區(qū)分 Proxy 和 Decorator 的使用場景,可以概括為:Proxy 的核心作用是控制外界對被代理者內(nèi)部的訪問,Decorator 的核心作用是增強(qiáng)被裝飾者的功能。只要在它們核心的使用場景上做好區(qū)別,那么像是訪問日志這樣的功能,雖然本文使用了 Proxy 實(shí)現(xiàn),但也可以使用 Decorator 實(shí)現(xiàn),開發(fā)者可以根據(jù)項(xiàng)目的需求、團(tuán)隊(duì)的規(guī)范、自己的偏好自由選擇。

    總結(jié)

    ES6 的 Proxy還是非常實(shí)用的,看似簡單的特性,卻有極大的用處。希望給大家學(xué)習(xí)ES6有所幫助。

    更多信息請查看網(wǎng)絡(luò)編程
    易賢網(wǎng)手機(jī)網(wǎng)站地址:詳細(xì)探究ES6之Proxy代理
    由于各方面情況的不斷調(diào)整與變化,易賢網(wǎng)提供的所有考試信息和咨詢回復(fù)僅供參考,敬請考生以權(quán)威部門公布的正式信息和咨詢?yōu)闇?zhǔn)!

    2026上岸·考公考編培訓(xùn)報(bào)班

    • 報(bào)班類型
    • 姓名
    • 手機(jī)號
    • 驗(yàn)證碼
    關(guān)于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 新媒體/短視頻平臺 | 手機(jī)站點(diǎn) | 投訴建議
    工業(yè)和信息化部備案號:滇ICP備2023014141號-1 云南省教育廳備案號:云教ICP備0901021 滇公網(wǎng)安備53010202001879號 人力資源服務(wù)許可證:(云)人服證字(2023)第0102001523號
    云南網(wǎng)警備案專用圖標(biāo)
    聯(lián)系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關(guān)注公眾號:hfpxwx
    咨詢QQ:1093837350(9:00—18:00)版權(quán)所有:易賢網(wǎng)
    云南網(wǎng)警報(bào)警專用圖標(biāo)