Heim  >  Artikel  >  Web-Frontend  >  Anweisungen zur Verwendung von Proxy in ES6

Anweisungen zur Verwendung von Proxy in ES6

亚连
亚连Original
2018-06-13 10:57:351545Durchsuche

Dieser Artikel stellt hauptsächlich die Verwendungsszenarien von ES6 Proxy vor. Jetzt teile ich ihn mit Ihnen und gebe ihn als Referenz.

Funktionen wie Pfeilfunktionen, Array-Destrukturierung und Restparameter wurden in ES6 sofort nach ihrer Implementierung weit verbreitet. Einerseits werden Funktionen wie Proxy von Entwicklern selten verwendet Um diese Funktionen nutzen zu können, müssen Entwickler andererseits ihre Nutzungsszenarien genau verstehen. Persönlich gefällt mir der Proxy von ES6 sehr gut, weil er es uns ermöglicht, den externen Zugriff auf Objekte auf übersichtliche und leicht verständliche Weise zu steuern. Im Folgenden werde ich zunächst die Verwendung von Proxy vorstellen und anschließend anhand konkreter Beispiele die Verwendungsszenarien von Proxy erläutern.

Proxy ist, wie der Name schon sagt, in seiner Funktion dem Proxy-Muster in Entwurfsmustern sehr ähnlich. Dieses Muster wird häufig in drei Aspekten verwendet:

  1. Abfangen und Überwachen von externen Transaktionen Objektzugriff

  2. Reduzieren Sie die Komplexität von Funktionen oder Klassen

  3. Überprüfen Sie Vorgänge oder verwalten Sie erforderliche Ressourcen vor komplexen Vorgängen

In einer Browserumgebung, die Proxy unterstützt, ist Proxy ein globales Objekt und kann direkt verwendet werden. Proxy(Ziel, Handler) ist ein Konstruktor, Ziel ist das Objekt, das als Proxy fungiert, Handler ist ein Objekt, das verschiedene Proxy-Operationen deklariert und letztendlich ein Proxy-Objekt zurückgibt. Jedes Mal, wenn die Außenwelt über das Proxy-Objekt auf die Eigenschaften des Zielobjekts zugreift, durchläuft sie das Handler-Objekt. In diesem Prozess ist das Proxy-Objekt der Middleware sehr ähnlich. Welche Operationen kann Proxy also abfangen? Die häufigsten Operationen sind das Abrufen (Lesen) und das Festlegen (Ändern) von Objekteigenschaften. Eine vollständige Liste der abfangbaren Operationen finden Sie hier. Darüber hinaus bietet das Proxy-Objekt auch eine Widerrufmethode, um alle Proxy-Vorgänge jederzeit abzumelden. Bevor wir Proxy offiziell einführen, wird empfohlen, dass Sie über ein gewisses Verständnis von Reflect verfügen. Es handelt sich auch um ein neues globales Objekt in ES6. Weitere Informationen finden Sie unter MDN Reflect.

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"

Im obigen Code definieren wir zunächst ein Proxy-Zielobjekt, deklarieren dann das Handler-Objekt, das alle Proxy-Operationen enthält, und erstellen dann mit Proxy(target, handler) ein Danach werden alle Zugriffe auf das Zielattribut über Proxy vom Handler verarbeitet.

1. Extrahieren Sie das Verifizierungsmodul

Lassen Sie uns mit einer einfachen Typüberprüfung beginnen. Dieses Beispiel zeigt, wie Proxy verwendet wird, um die Genauigkeit von Datentypen sicherzustellen:

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);
  }
});

// 抛出错误,因为 "foo" 不是数值
numericDataStore.count = "foo";

// 赋值成功
numericDataStore.count = 333;

Wenn Sie einen Validator für alle Eigenschaften eines Objekts direkt entwickeln möchten, kann die Codestruktur schnell aufgebläht werden. Mit Proxy können Sie den Validator von der Kernlogik trennen und ihn in sich geschlossen machen:

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);

// 以下操作都会报错
bill.name = 0; 
bill.age = 'Bill'; 
bill.age = 15;

Durch die Trennung des Validators und der Hauptlogik können Sie den Inhalt des PersonValidators-Validators unendlich erweitern, ohne direkte Schäden an verwandten Klassen oder Funktionen zu verursachen. Um es komplizierter zu machen, können wir Proxy auch verwenden, um die Typprüfung zu simulieren und zu prüfen, ob die Funktion den richtigen Typ und die richtige Anzahl von Parametern erhält:

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 Private Attribute

in In JavaScript und anderen Sprachen ist es üblich, vor einem Variablennamen einen Unterstrich _ einzufügen, um anzuzeigen, dass es sich um eine private Eigenschaft (nicht wirklich privat) handelt. Wir können jedoch nicht garantieren, dass niemand darauf zugreifen oder sie ändern wird. Im folgenden Code deklarieren wir einen privaten apiKey, um Methodenaufrufe innerhalb des API-Objekts zu erleichtern, möchten aber nicht von außen auf die API zugreifen können._apiKey:

var api = { 
  _apiKey: &#39;123abc456def&#39;,
  /* mock methods that use this._apiKey */
  getUsers: function(){}, 
  getUser: function(userId){}, 
  setUser: function(userId, config){}
};

// logs &#39;123abc456def&#39;;
console.log("An apiKey we want to keep private", api._apiKey);

// get and mutate _apiKeys as desired
var apiKey = api._apiKey; 
api._apiKey = &#39;987654321&#39;;

Offensichtlich ist die Konvention nicht so Bindung von. Mit ES6 Proxy können wir echte private Variablen implementieren. Im Folgenden werden zwei verschiedene Privatisierungsmethoden für unterschiedliche Lesemethoden gezeigt. Die erste Methode besteht darin, set / get zu verwenden, um Lese- und Schreibanforderungen abzufangen und undefiniert zurückzugeben:

let api = { 
  _apiKey: &#39;123abc456def&#39;,
  getUsers: function(){ }, 
  getUser: function(userId){ }, 
  setUser: function(userId, config){ }
};

const RESTRICTED = [&#39;_apiKey&#39;];
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);
  }
});

// 以下操作都会抛出错误
console.log(api._apiKey);
api._apiKey = &#39;987654321&#39;;

Die zweite Methode besteht darin, has to intercept in Operationen zu verwenden:

var api = { 
  _apiKey: &#39;123abc456def&#39;,
  getUsers: function(){ }, 
  getUser: function(userId){ }, 
  setUser: function(userId, config){ }
};

const RESTRICTED = [&#39;_apiKey&#39;];
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. Zugriffsprotokoll

Für häufig aufgerufene Eigenschaften oder Schnittstellen, die langsam ausgeführt werden oder viele Ressourcen der Ausführungsumgebung beanspruchen, möchten Entwickler deren Nutzung oder Leistung zu diesem Zeitpunkt aufzeichnen Wird als Middleware-Rolle verwendet, ist es einfach, die Protokollierungsfunktion zu implementieren:

let api = { 
  _apiKey: &#39;123abc456def&#39;,
  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. Angenommen, Sie möchten nicht, dass andere Entwickler dies tun Löschen Sie das noDelete-Attribut, und Sie möchten auch, dass Entwickler oldMethod aufrufen. Nachdem Sie erfahren haben, dass diese Methode aufgegeben wurde, oder Entwickler angewiesen haben, das doNotChange-Attribut nicht zu ändern, können Sie Proxy verwenden, um es zu implementieren:

let dataStore = { 
  noDelete: 1235,
  oldMethod: function() {/*...*/ },
  doNotChange: "tried and true"
};

const NODELETE = [&#39;noDelete&#39;]; 
const NOCHANGE = [&#39;doNotChange&#39;];
const DEPRECATED = [&#39;oldMethod&#39;]; 

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 === &#39;function&#39; ?
      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. Filtervorgang

Einige Einige Vorgänge verbrauchen viele Ressourcen, z. B. die Übertragung großer Dateien. Wenn die Datei zu diesem Zeitpunkt bereits in Blöcken gesendet wird, besteht keine Notwendigkeit, darauf zu reagieren Neue Anfragen (nicht absolut). Zu diesem Zeitpunkt können Sie Proxy verwenden, um eine Funktionserkennung für die aktuelle Anfrage durchzuführen und basierend auf den Merkmalen herauszufiltern, was keine Antwort erfordert. Der folgende Code zeigt einfach, wie man Funktionen filtert. Ich glaube, jeder wird das Schöne daran verstehen:

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-Unterstützung Den Proxy des Ziels jederzeit abbrechen. Dieser Vorgang wird häufig verwendet, um den Zugriff auf Daten oder Schnittstellen vollständig zu sperren. Im folgenden Beispiel verwenden wir die Proxy.revocable-Methode, um ein Proxy-Objekt für einen widerrufbaren Proxy zu erstellen:

let sensitiveData = { username: &#39;devbryce&#39; };
const {sensitiveData, revokeAccess} = Proxy.revocable(sensitiveData, handler);
function handleSuspectedHack(){ 
  revokeAccess();
}

// logs &#39;devbryce&#39;
console.log(sensitiveData.username);
handleSuspectedHack();
// TypeError: Revoked
console.log(sensitiveData.username);

Decorator

Der in ES7 implementierte Decorator entspricht dem Decorator-Muster im Designmuster. Wenn wir einfach die Verwendungsszenarien von Proxy und Decorator unterscheiden, kann dies wie folgt zusammengefasst werden: Die Kernfunktion von Proxy besteht darin, den externen Zugriff auf das Innere des Proxys zu steuern, und die Kernfunktion von Decorator besteht darin, die Funktion des Proxys zu verbessern Dekorateur. Solange ihre Kernnutzungsszenarien unterschieden werden, können Funktionen wie Zugriffsprotokolle, obwohl dieser Artikel Proxy zu ihrer Implementierung verwendet, auch mithilfe von Decorator implementiert werden. Entwickler können sie basierend auf Projektanforderungen, Teamspezifikationen und ihren eigenen Vorlieben implementieren Auswahl.

Ich habe das Obige für Sie zusammengestellt und hoffe, dass es Ihnen in Zukunft hilfreich sein wird.

Verwandte Artikel:

So führen Sie öffentliche CSS-Dateien über Vue ein

Welche Methoden gibt es zur Verwendung von Ajax in Vue?

So implementieren Sie den Datenverteilungsslot in vue.js

Das obige ist der detaillierte Inhalt vonAnweisungen zur Verwendung von Proxy in ES6. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn