什么是Proxy?

Proxy对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)

 

语法

const p = new Proxy(target, handler)

参数说明

target 要使用Proxy包装的目标对象
handler 处理器对象

 

 

 

创建一个可撤销的Proxy对象

Proxy.revocable()

 

基础示例

const handler = {
  get: function(obj, prop) {
    return prop in obj ? obj[prop] : 37
  }
}

const p = new Proxy({}, handler)
p.a = 1
p.b = undefined

console.log(p.a, p.b) // 1, undefined
console.log('c' in p, p.c) // false, 37

 

无操作转发代理

let target = {}
let p = new Proxy(target, {})

p.a = 37 // 操作转发到目标

console.log(target.a) // 37

 

验证

通过代理,你可以轻松地验证向一个对象的传值。

 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 
12     obj[prop] = value;
13 
14     return true; // 表示成功
15   }
16 }
17 
18 let person = new Proxy({}, validator)
19 
20 person.age = 100
21 
22 console.log(person.age)
23 
24 person.age = 'young'
25 person.age = 300

 

操作DOM节点

有时候可能需要互换两个不同元素的属性或类名,下面的代码以此为目标,展示了set handler的使用场景

let view = new Proxy({
  selected: null
}, {
  set: function(obj, prop, newval) {
    let objval = obj[prop]

    if (prop === 'selected') {
      if (oldval) {
        oldval.setAttribute('aria-selected', 'false')
      }
      if (newval) {
        newval.setAttribute('aria-selected', 'true')
      }
    }

    obj[prop] = newval

    return true; // 表示操作成功
  }
})

let i1 = view.selected = document.getElementById('item-1')
console.log(i1.getAttribute('aria-selected')) // 'true'

let i2 = view.selected = document.getElementById('item-2')
console.log(i1.getAttribute('aria-selected')) // 'false'
console.log(i2.getAttribute('aria-selected')) // 'true'

 

通过属性查找数组中的特定对象

以下代理为数组扩展了一些实用工具。

let products = new Proxy([{
  name: 'Firefox',
  type: 'browser'
}, {
  name: 'SeaMonkey',
  type: 'browser'
},
{
  name: 'Thunderbird',
  type: 'mailer'
}], {
  get: function(obj, prop) {
    // 默认行为是返回属性值,prop通常是一个整数
    if (prop in obj) {
      return obj[prop]
    }

    if (prop === 'number') {
      return obj.length
    }

    let result, types = {};

    for (let product of obj) {
      if (product.name === prop) {
        result = product;
      }
      if (types[product.type]) {
        types[product.type].push(product)
      } else {
        types[product.type] = [product]
      }
    }

    // 通过name获取product
    if (result) {
      return result;
    }

    // 通过type获取products
    if (prop in types) {
      return types[prop]
    }

    // 获取product type
    if (prop === 'types') {
      return Object.keys(types)
    }

    return undefined;
  }
})

// console.log(products[0])
// console.log(products['Firefox'])
console.log(products['Chrome']) // undefined
console.log(products.browser)
console.log(products.types) // ['browser', 'mailer']
console.log(products.number) // 3

 

 

内容摘自文档:

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy

posted on 2023-04-27 19:09  白小鸽  阅读(25)  评论(0编辑  收藏  举报