目录

  • Proxy
  • Basic Syntax(根本用法)
  • Schema Validation —— 只读
  • Schema Validation —— 校验
  • Schema Validation —— 监控上报
  • Schema Validation —— 惟一只读id
  • Revocable Proxies —— 撤销代理
  • Proxy VS Object.defineProperty()

      1. proxy监督的操作更广
      1. Proxy更好的反对数组对象的监督
      • 如何应用Proxy对数组进行监督?
      1. Proxy是以非侵入的形式监管了对象的读写
  • ES6-ES10学习幅员

Proxy

ES6 规范中新增的一个十分弱小的性能是 Proxy,它能够自定义一些罕用行为如查找、赋值、枚举、函数调用等。通过 Proxy 这个名称也能够看进去它蕴含了“代理”的含意,只有有“代理”的诉求都能够思考应用 Proxy 来实现。

PS: 相似租房找中介,中介能够屏蔽原始信息。

Basic Syntax

let p = new Proxy(target, handler)
参数含意必选
target用 Proxy 包装的指标对象(能够是任何类型的对象,包含原生数组,函数,甚至另一个代理)Y
handler一个对象,其属性是当执行一个操作时定义代理的行为的函数Y

第一个参数 target 就是用来代理的“对象”,被代理之后它是不能间接被拜访的,而 handler 就是实现代理的过程。

//o是房东的角色,被代理的对象let o = {  name: 'xiaoming',  price: 190}// d是一个中介的角色,代理let d = new Proxy(o, {})console.log(d.price, d.name) // 190 'xiaoming'// 因为传的是空对象,所以是透传let d = new Proxy(o, {  get(target, key) { //target是指o,代理的对象,key指的是属性    if(key === 'price') { // 如果等于价格的时候进行加20的操作      return target[key] + 20    } else {      return target[key]    }  }})console.log(d.price, d.name) //210 "xiaoming"
let o = {  name: 'xiaoming',  age: 20}console.log(o.name) // xiaomingconsole.log(o.age) // 20console.log(o.from) // undefined// 当咱们读取from的时候,因为o外面没有这个属性,所以返回undefined,如果咱们不想在调用的时候呈现undefined// ES5形式解决// console.log(o.from || '')// ES6形式解决let o = {  name: 'xiaoming',  age: 20}let handler = {  get(obj, key) {    return Reflect.has(obj, key) ? obj[key] : ''  }}let p = new Proxy(o, handler)console.log(p.from) // ''

Schema Validation —— 只读

拿走备份,不影响原始数据

在ES5中的利用

let o = {  name: 'xiaoming',  price: 190}for(let [key] of Object.entries(o)) {  Object.defineProperty(o, key, {    writable: false  })}console.log(o.name, o.price)// xiaoming 190o.price = 300console.log(o.name, o.price)// xiaoming 190

ES6

let o = {  name: 'xiaoming',  price: 190}let d = new Proxy(o, {  get (target, key) {      return target[key]  },  set (target, key, value) {      return false  }})//只读不能写d.price = 300console.log(d.price, d.name)// 190 "xiaoming"

和代理的区别,在于这个全副锁死,然而ES6中用户只读,然而代理能够做操作

Schema Validation —— 校验

判断如果价格 >300 就不让批改,如果没有这个属性就返回空字符串

let o = {  name: 'xiaoming',  price: 190}let d = new Proxy(o, {  get (target, key) {    return target[key] || ''  },  set (target, key, value) {    if (Reflect.has(target, key)) {      if (key === 'price') {        if(value > 300){          return false        } else {          target[key] = value        }       } else {        target[key] = value      }    } else {      return false    }  }})d.price = 280console.log(d.price, d.name)// 280 "xiaoming"d.price = 301 // 没有失效,因为校验没有通过d.name = 'xiaohong'console.log(d.price, d.name)// 280 "xiaohong"d.age = 40 // 没有这个属性,set时候返回,get的时候赋值为空字符串console.log(d.price, d.name, d.age)// 280 "xiaohong" ""

去掉耦合,将验证函数抽离成一个验证函数

let o = {  name: 'xiaoming',  price: 190}let validator = (target, key, value) => {  if (Reflect.has(target, key)) {    if (key === 'price') {      if(value > 300){        return false      } else {        target[key] = value      }     } else {      target[key] = value    }  } else {    return false  }}let d = new Proxy(o, {  get (target, key) {    return target[key] || ''  },  set: validator})d.price = 280console.log(d.price, d.name)// 280 "xiaoming"d.price = 301d.name = 'xiaohong'console.log(d.price, d.name)// 280 "xiaohong"d.age = 40console.log(d.price, d.name, d.age)// 280 "xiaohong" ""

整顿成一个组件

// Validator.jsexport default (obj, key, value) => {  if (Reflect.has(key) && value > 20) {    obj[key] = value  }}import Validator from './Validator'let data = new Proxy(response.data, {  set: Validator})

Schema Validation —— 监控上报

window.addEventListener('error', (e) => {  console.log(e.message)  // 上报  // report('...')}, true) //捕捉let o = {  name: 'xiaoming',  price: 190}let validator = (target, key, value) => {  if (Reflect.has(target, key)) {    if (key === 'price') {      if(value > 300){        //不满足要触发谬误        throw new TypeError('price exceed 300')      } else {        target[key] = value      }     } else {      target[key] = value    }  } else {    return false  }}let d = new Proxy(o, {  get (target, key) {    return target[key] || ''  },  set: validator})d.price = 280console.log(d.price, d.name)// 280 "xiaoming"d.price = 301d.name = 'xiaohong'console.log(d.price, d.name)// 280 "xiaohong"d.age = 40console.log(d.price, d.name, d.age)// 280 "xiaohong" ""

Schema Validation —— 惟一只读id

  1. 每次生成一个id
  2. 不可批改
  3. 每个实例的id互不雷同
// 摸索一class Component {  constructor() {    this.id = Math.random().toString(36).slice(-8)  }}let com = new Component()let com2 = new Component()for (let i = 0 ; i < 10 ; i++) {  console.log(com.id)}for (let i = 0 ; i < 10 ; i++) {  console.log(com2.id)}com.id = 'abc'console.log(com.id,com2.id)// 这种形式能够每次生成一个id,然而能够批改,不符合要求// (10) 4robfncs// (13) 93ukz26i// 能够批改// abc 93ukz26i
// 摸索二class Component {  get id () {    return Math.random().toString(36).slice(-8)  }}let com = new Component()let com2 = new Component()for (let i = 0 ; i < 10 ; i++) {  console.log(com.id)}for (let i = 0 ; i < 10 ; i++) {  console.log(com2.id)}com.id = 'abc'console.log(com.id,com2.id)// 这种形式不能够批改,然而每此都生成了一个新的,不符合要求// nqwlamib// l9ojsjiq// gad3vm2a// i1jew3bd// owquntob// rcpce268// va6mry5v// lvqxv0m4// a900358x// jahi7079// vukusf5k// rg8hyzf3// 50vxv0hk// tjeyes1v// 4g8zwsxz// 5r1cbx1k// v9k2v7hd// 0mgn3heb// n0zc9v66// rdjevl2i// 9rjmwrd9 kxdxtywe
// 摸索三class Component {  constructor() {    this.proxy = new Proxy({      id: Math.random().toString(36).slice(-8)    }, {})  }  get id () {    return this.proxy.id  }}let com = new Component()let com2 = new Component()for (let i = 0 ; i < 10 ; i++) {  console.log(com.id)}for (let i = 0 ; i < 10 ; i++) {  console.log(com2.id)}com.id = 'abc'console.log(com.id,com2.id)// 满足要求// (10)e9e8jsks// (10)tfs2rrvg// e9e8jsks tfs2rrvg

Revocable Proxies —— 撤销代理

除了惯例代理,还能够创立长期代理,长期代理能够撤销。

一旦revoke被调用,proxy就生效了,就起到了长期代理的作用。

let o = {  name: 'xiaoming',  price: 190}// 这里不能应用new,只能应用Proxy.revocable去申明代理let d = Proxy.revocable(o, {  get(target, key) {    if(key === 'price') {      return target[key] + 20    } else {      return target[key]    }  }})// d外面蕴含了代理数据和撤销操作console.log(d.proxy.price) // 210console.log(d) // {proxy: Proxy, revoke: ƒ}setTimeout(function(){  // 对代理进行撤销操作  d.revoke()  setTimeout(function(){    console.log(d.proxy.price)    // Uncaught TypeError: Cannot perform 'get' on a proxy that has been revoked  },100)},1000)

Proxy VS Object.defineProperty()

如果想要监听某个对象属性的扭转,能够应用Object.defineProperty这个办法去增加属性,那么就能够捕捉到对象中属性的读写过程, VUE3.0之前的版本就是通过这个实现的数据双向绑定。从VUE3.0开始就应用proxy来实现外部响应了。

proxy是专门为对象设置代理器的,那么proxy就能够轻松监督到对象的读写过程。相比拟definePropertyproxy的性能更加弱小,应用起来也更为不便。

1. proxy监督的操作更广

defineProperty只能监督属性的读写,proxy可能监督到更多对象的操作,例如删除属性操作

const person = {  name: 'xm',  age: 20}const personProxy = new Proxy(person, {  deleteProperty (target, property) {    console.log('delete ' + property) // delete age    delete target[property]  }}) delete personProxy.ageconsole.log(person) // { name: 'xm' }
handler ⽅法触发⽅式
get读取某个属性
set写⼊某个属性
hasin 操作符
deletePropertydelete 操作符
getPropertyObject.getPropertypeOf()
setPropertyObject.setPrototypeOf()
isExtensibleObject.isExtensible()
preventExtensionsObject.preventExtensions()
getOwnPropertyDescriptorObject.getOwnPropertyDescriptor()
definePropertyObject.defineProperty()
ownKeysObject.keys() 、Object.getOwnPropertyNames()、Object.getOwnPropertySymbols()
apply调⽤⼀个函数
construct⽤ new 调⽤⼀个函数

2. Proxy更好的反对数组对象的监督

以往Object.defineProperty()应用的是重写数组的操作方法

如何应用Proxy对数组进行监督?

const list = []const listProxy = new Proxy(list, {  set(target, property, value) {    console.log('set', property, value)    target[property] = value    return true // 示意设置胜利  }})listProxy.push(100)// set 0 100// set length 1listProxy.push(200)// set 1 200// set length 2

3. Proxy是以非侵入的形式监管了对象的读写

ES6-ES10学习幅员