js Proxy 的使用

一、什么是Proxy

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

二、语法

var proxy = new Proxy(target, handler);

解释: Proxy 对象的所有用法,都是上面这种形式,不同的只是handler参数的写法。其中,new Proxy()表示生成一个Proxy实例target参数表示所要拦截的目标对象handler参数也是一个对象,用来定制拦截行为

三、Proxy 方法

1、get() 方法

get方法用于拦截某个属性的读取操作,可以接受三个参数,依次为目标对象属性名proxy 实例本身(严格地说,是操作行为所针对的对象),其中最后一个参数可选。

语法:

var handler = {
    
    
  get (target, propKey, ctx) {
    
    
  	return target[propKey];
  }
};

例:

var person = {
    
    
  name: "张三"
};

var proxy = new Proxy(person, {
    
    
  get: function(target, propKey) {
    
    
    if (propKey in target) {
    
    
      return target[propKey];
    } else {
    
    
      throw new ReferenceError("Prop name \"" + propKey + "\" does not exist.");
    }
  }
});

console.log(proxy.name) // "张三"
console.log(proxy.age) // 抛出一个错误

运行结果:

在这里插入图片描述

解释: 上面代码表示,如果访问目标对象不存在的属性,会抛出一个错误。如果没有这个拦截函数,访问不存在的属性,只会返回undefined。

2、set() 方法

set方法用来拦截某个属性的赋值操作,可以接受四个参数,依次为目标对象属性名属性值Proxy 实例本身,其中最后一个参数可选。

语法:

var handler = {
    
    
  set (target, propKey, propValue, ctx) {
    
    
  	target[propKey] = propValue;
  }
};

例:

let validator = {
    
    
  set: function(obj, prop, value) {
    
    
    if (prop === '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 属性以及其他属性,直接保存
    obj[prop] = value;
    return true;
  }
};

let person = new Proxy({
    
    }, validator);

person.age = 100;

console.log(person.age) // 100
person.age = 'young' // 报错
person.age = 300 // 报错

运行结果:

在这里插入图片描述
解释: 上面代码中,由于设置了存值函数set,任何不符合要求的age属性赋值,都会抛出一个错误,这是数据验证的一种实现方法。利用set方法,还可以数据绑定,即每当对象发生变化时,会自动更新 DOM。

3、apply() 方法

apply方法拦截函数的调用callapply操作。apply方法可以接受三个参数,分别是目标对象、目标对象的上下文对象(this)和目标对象的参数数组

语法:

var handler = {
    
    
  apply (target, ctx, args) {
    
    
    return Reflect.apply(...arguments);
  }
};

例:

var target = function () {
    
     return 'I am the target'; };
var handler = {
    
    
  apply: function () {
    
    
    return 'I am the proxy';
  }
};

var p = new Proxy(target, handler);

p()

运行结果:

在这里插入图片描述

解释: 上面代码中,变量p是 Proxy 的实例,当它作为函数调用时(p()),就会被apply方法拦截,返回一个字符串。

4、has() 方法

has()方法用来拦截HasProperty操作,即判断对象是否具有某个属性时,这个方法会生效。典型的操作就是in运算符。has()方法可以接受两个参数,分别是目标对象、需查询的属性名

语法:

var handler = {
    
    
  has (target, propKey) {
    
    
  	return propKey in target;
  }
};

例:

var handler = {
    
    
  has (target, key) {
    
    
    if (key[0] === '_') {
    
    
      return false;
    }
    return key in target;
  }
};
var target = {
    
     _prop: 'foo', prop: 'foo' };
var proxy = new Proxy(target, handler);

flag = 'prop' in proxy 
alert(flag)

运行结果:

在这里插入图片描述

解释: 上面代码中,如果原对象的属性名的第一个字符是下划线,proxy.has()就会返回false,从而不会被in运算符发现。

5、construct() 方法

construct()方法用于拦截new命令,下面是拦截对象的写法。construct()方法可以接受三个参数: 目标对象、构造函数的参数数组、目标对象的上下文对象(this)

语法:

var handler = {
    
    
  construct (target, args, ctx) {
    
    
  	return new target(...args);
  }
};

例:

const p = new Proxy(function () {
    
    }, {
    
    
  construct: function(target, args) {
    
    
    console.log('called: ' + args.join(', '));
    return {
    
     value: args[0] * 10 };
  }
});

console.log((new p(1)).value)

运行结果:

在这里插入图片描述

解释: construct()方法返回的必须是一个对象,否则会报错。

6、deleteProperty() 方法

deleteProperty方法用于拦截delete操作,如果这个方法抛出错误或者返回false,当前属性就无法被delete命令删除。deleteProperty() 方法接受两个参数:目标对象目标属性

语法:

var handler = {
    
    
  deleteProperty (target, propKey) {
    
    
  	delete target[propKey];
  }
};

例:

var handler = {
    
    
  deleteProperty (target, key) {
    
    
    invariant(key, 'delete');
    delete target[key];
    return true;
  }
};
function invariant (key, action) {
    
    
  if (key[0] === '_') {
    
    
    throw new Error(`Invalid attempt to ${
      
      action} private "${
      
      key}" property`);
  }
}

var target = {
    
     _prop: 'foo' };
var proxy = new Proxy(target, handler);
delete proxy._prop
// Error: Invalid attempt to delete private "_prop" property

运行结果:

在这里插入图片描述

解释: 上面代码中,deleteProperty方法拦截了delete操作符,删除第一个字符为下划线的属性会报错。

猜你喜欢

转载自blog.csdn.net/change_any_time/article/details/128521279