关于javascript:ES6十三-Rroxy

9次阅读

共计 6457 个字符,预计需要花费 17 分钟才能阅读完成。

目录

  • 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) // xiaoming
console.log(o.age) // 20
console.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 190
o.price = 300
console.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 = 300
console.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 = 280
console.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 = 280
console.log(d.price, d.name)// 280 "xiaoming"
d.price = 301
d.name = 'xiaohong'
console.log(d.price, d.name)// 280 "xiaohong"
d.age = 40
console.log(d.price, d.name, d.age)// 280 "xiaohong" ""

整顿成一个组件

// Validator.js
export 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 = 280
console.log(d.price, d.name)// 280 "xiaoming"
d.price = 301
d.name = 'xiaohong'
console.log(d.price, d.name)// 280 "xiaohong"
d.age = 40
console.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) // 210
console.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.age

console.log(person) // {name: 'xm'}
handler ⽅法 触发⽅式
get 读取某个属性
set 写⼊某个属性
has in 操作符
deleteProperty delete 操作符
getProperty Object.getPropertypeOf()
setProperty Object.setPrototypeOf()
isExtensible Object.isExtensible()
preventExtensions Object.preventExtensions()
getOwnPropertyDescriptor Object.getOwnPropertyDescriptor()
defineProperty Object.defineProperty()
ownKeys Object.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 1

listProxy.push(200)
// set 1 200
// set length 2

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

ES6-ES10 学习幅员

正文完
 0