当前位置:   article > 正文

ES6之Proxy代理器(拦截)_es6 proxy 拦截 方法调用

es6 proxy 拦截 方法调用

Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例。

  1. var obj = new Proxy({}, {
  2. get: function (target, propKey, receiver) {
  3. console.log(target); // 目标对象:拦截和改写的对象
  4. console.log(prop); // 对象属性
  5. console.log(receiver); // proxy对象本身
  6. return Reflect.get(target, propKey, receiver);
  7. },
  8. set: function (target, propKey, value, receiver) {
  9. console.log(value); // 属性设置值
  10. return Reflect.set(target, propKey, value, receiver);
  11. }
  12. });
  13. obj.count = 1
  14. // setting count!
  15. ++obj.count
  16. // getting count!
  17. // setting count!
  18. // 2

同一个拦截器函数,可以设置拦截多个操作。proxy对象是obj对象的原型,obj对象本身并没有time属性,所以根据原型链,会在proxy对象上读取该属性,导致被拦截。

  1. var proxy = new Proxy({}, {
  2. get: function(target, propKey) {
  3. return 35;
  4. }
  5. });
  6. let obj = Object.create(proxy);
  7. obj.time // 35

拦截操作:

  • get(target, propKey, receiver):拦截对象属性的读取,比如proxy.fooproxy['foo']
  • set(target, propKey, value, receiver):拦截对象属性的设置,比如proxy.foo = vproxy['foo'] = v,返回一个布尔值。
  • has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值。
  • deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回一个布尔值。
  • ownKeys(target):拦截Object.getOwnPropertyNames(proxy)Object.getOwnPropertySymbols(proxy)Object.keys(proxy)for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。
  • getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
  • defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)Object.defineProperties(proxy, propDescs),返回一个布尔值。
  • preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值。
  • getPrototypeOf(target):拦截Object.getPrototypeOf(proxy),返回一个对象
  • isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值。
  • setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
  • apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)proxy.call(object, ...args)proxy.apply(...)
  • construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)

get:利用 Proxy,可以将读取属性的操作(get),转变为执行某个函数,从而实现属性的链式操作。

  1. var pipe = function (value) {
  2. var funcStack = [];
  3. var oproxy = new Proxy({} , {
  4. get : function (pipeObject, fnName) {
  5. if (fnName === 'get') {
  6. return funcStack.reduce(function (val, fn) {
  7. return fn(val);
  8. },value);
  9. }
  10. funcStack.push(window[fnName]);
  11. return oproxy;
  12. }
  13. });
  14. return oproxy;
  15. }
  16. var double = n => n * 2;
  17. var pow = n => n * n;
  18. var reverseInt = n => n.toString().split("").reverse().join("") | 0;
  19. pipe(3).double.pow.reverseInt.get; // 63

set:假定Person对象有一个age属性,该属性应该是一个不大于 200 的整数,那么可以使用Proxy保证age的属性值符合要求。

  1. let validator = {
  2. set: function(obj, prop, value) {
  3. if (prop === 'age') {
  4. if (!Number.isInteger(value)) {
  5. throw new TypeError('The age is not an integer');
  6. }
  7. if (value > 200) {
  8. throw new RangeError('The age seems invalid');
  9. }
  10. }
  11. // 对于满足条件的 age 属性以及其他属性,直接保存
  12. obj[prop] = value;
  13. }
  14. };
  15. let person = new Proxy({}, validator);
  16. person.age = 100;
  17. person.age // 100
  18. person.age = 'young' // 报错
  19. person.age = 300 // 报错

apply: 每当执行proxy函数(直接调用或callapply调用),就会被apply方法拦截。

  1. var twice = {
  2. apply (target, ctx, args) {
  3. return Reflect.apply(...arguments) * 2;
  4. }
  5. };
  6. function sum (left, right) {
  7. return left + right;
  8. };
  9. var proxy = new Proxy(sum, twice);
  10. proxy(1, 2) // 6
  11. proxy.call(null, 5, 6) // 22
  12. proxy.apply(null, [7, 8]) // 30

has:用来拦截HasProperty操作,即判断对象是否具有某个属性时(但是has()拦截对for...in循环不生效。)

  1. var handler = {
  2. has (target, key) {
  3. if (key[0] === '_') {
  4. return false;
  5. }
  6. return key in target;
  7. }
  8. };
  9. var target = { _prop: 'foo', prop: 'foo' };
  10. var proxy = new Proxy(target, handler);
  11. '_prop' in proxy // false

construct: 用于拦截new命令

  1. const handler = {
  2. construct (target, args, newTarget) {
  3. return new target(...args);
  4. }
  5. };
  6. 1-construct()方法返回的必须是一个对象,否则会报错。
  7. 2-由于construct()拦截的是构造函数,所以它的目标对象必须是函数,否则就会报错。
  8. const p = new Proxy(function () {}, {
  9. construct: function(target, args) {
  10. console.log('called: ' + args.join(', '));
  11. return { value: args[0] * 10 };
  12. }
  13. });
  14. (new p(1)).value
  15. // "called: 1"
  16. // 10

deleteProperty: 用于拦截delete操作,如果这个方法抛出错误或者返回false,当前属性就无法被delete命令删除。

  1. var handler = {
  2. deleteProperty (target, key) {
  3. invariant(key, 'delete');
  4. delete target[key];
  5. return true;
  6. }
  7. };
  8. function invariant (key, action) {
  9. if (key[0] === '_') {
  10. throw new Error(`Invalid attempt to ${action} private "${key}" property`);
  11. }
  12. }
  13. var target = { _prop: 'foo' };
  14. var proxy = new Proxy(target, handler);
  15. delete proxy._prop
  16. // Error: Invalid attempt to delete private "_prop" property

defineProperty()方法拦截了Object.defineProperty()操作。

  1. defineProperty()方法内部没有任何操作,只返回false,导致添加新属性总是无效。
  2. 注意,这里的false只是用来提示操作失败,本身并不能阻止添加新属性
  3. var handler = {
  4. defineProperty (target, key, descriptor) {
  5. return false;
  6. }
  7. };
  8. var target = {};
  9. var proxy = new Proxy(target, handler);
  10. proxy.foo = 'bar' // 不会生效

getOwnPropertyDescriptor()方法拦截Object.getOwnPropertyDescriptor(),返回一个属性描述对象或者undefined

  1. var handler = {
  2. getOwnPropertyDescriptor (target, key) {
  3. if (key[0] === '_') {
  4. return;
  5. }
  6. return Object.getOwnPropertyDescriptor(target, key);
  7. }
  8. };
  9. var target = { _foo: 'bar', baz: 'tar' };
  10. var proxy = new Proxy(target, handler);
  11. Object.getOwnPropertyDescriptor(proxy, 'wat')
  12. // undefined
  13. Object.getOwnPropertyDescriptor(proxy, '_foo')
  14. // undefined
  15. Object.getOwnPropertyDescriptor(proxy, 'baz')
  16. // { value: 'tar', writable: true, enumerable: true, configurable: true }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/140099
推荐阅读
  

闽ICP备14008679号