ES6(十三)—— Rroxy

目錄

  • 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 來實現。app

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

Basic Syntax

let p = new Proxy(target, handler)
參數 含義 必選
target 用 Proxy 包裝的目標對象(能夠是任何類型的對象,包括原生數組,函數,甚至另外一個代理) Y
handler 一個對象,其屬性是當執行一個操做時定義代理的行爲的函數 Y

第一個參數 target 就是用來代理的「對象」,被代理以後它是不能直接被訪問的,而 handler 就是實現代理的過程。dom

//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

ES6this

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中用戶只讀,可是代理能夠作操做spa

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" ""

整理成一個組件code

// 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學習版圖

相關文章
相關標籤/搜索