文章目录

  • 1. 基本语法
  • 2. 拦截操作场景
  • 3. 常用操作

在 ES6 标准中新增的一个非常强大的功能是 Proxy,它可以自定义一些常用行为如查找、赋值、枚举、函数调用等。通过 Proxy 这个名称也可以看出来它包含了“代理”的含义,只要有“代理”的诉求都可以考虑使用 Proxy 来实现。

1. 基本语法

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

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

2. 拦截操作场景

let obj = {name: 'xiaoming',age: 18
}
console.log(obj.telephone) // undefined

当我们读取 telephone 的时候返回的是 undefined,因为 obj 这个对象中没有这个属性。一般我们的做法是obj.telephone || '',这样能保证不会输出undefined,但如果都是这样写有点不太美观。ES6 的 Proxy 可以让我们轻松的解决这一问题:

let obj = {name: 'xiaoming',age: 18
}
let handle = {get (obj, key) {return Reflect.has(obj, key) ? obj[key] : ''}
}
let p = new Proxy(obj, handle)
console.log(p.telephone)

场景1:从服务端获取的数据希望是只读,不允许在任何一个环节被修改

// ES5 遍历设置只读
for (let [key] of Object.entries(response.data)) {Object.defineProperty(response.data, key, {writable: false})
}
// ES6 Proxy
let data = new Proxy(response.data, {set(obj, key, value) {return false}
})

场景2:校验,避免与业务逻辑耦合

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

场景3:对读写进行监控

let validator = {set(target, key, value) {if (key === 'age') {if (typeof value !== 'number' || Number.isNaN(value)) {throw new TypeError('Age must be a number')}if (value <= 0) {throw new TypeError('Age must be a positive number')}}return true}
}
const person = {age: 27
}
const proxy = new Proxy(person, validator)
proxy.age = 'foo'
// <- TypeError: Age must be a number
proxy.age = NaN
// <- TypeError: Age must be a number
proxy.age = 0
// <- TypeError: Age must be a positive number
proxy.age = 28
console.log(person.age)
// <- 28// 添加监控
window.addEventListener('error',e => {console.log(e.message) // Uncaught TypeError: Age must be a number},true
)

3. 常用操作

get 拦截对象属性的读取

let arr = [7, 8, 9]
arr = new Proxy(arr, {get(target, prop) {return prop in target ? target[prop] : 'error'}
})
console.log(arr[1]) // 8
console.log(arr[10]) // error

set 拦截对象属性的设置

let arr = []
arr = new Proxy(arr, {set(target, prop, val) {if (typeof val === 'number') {target[prop] = valreturn true} else {return false}}
})
arr.push(5)
arr.push(6)
console.log(arr[0], arr[1], arr.length)  // 5  6  2

has 拦截propKey in proxy的操作

let range = {start: 1,end: 5
}range = new Proxy(range, {has(target, prop) {return prop >= target.start && prop <= target.end}
})
console.log(2 in range) // true
console.log(9 in range) // false

ownKeys 拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for…in循环,返回一个数组

let userinfo = {username: 'xiecheng',age: 34,_password: '***'
}
userinfo = new Proxy(userinfo, {ownKeys(target) {return Object.keys(target).filter(key => !key.startsWith('_'))}
})
console.log(Object.keys(userinfo))  // ["username", "age"]

deleteProperty 拦截delete proxy[propKey]的操作

let user = {name: 'xiecheng',age: 34,_password: '***'
}
user = new Proxy(user, {deleteProperty(target, prop) { // 拦截删除if (prop.startsWith('_')) {throw new Error('不可删除')} else {delete target[prop]return true}}
})
delete user._password // Uncaught Error: 不可删除

apply 拦截 Proxy 实例作为函数调用的操作

let sum = (...args) => {let num = 0args.forEach(item => {num += item})return num
}sum = new Proxy(sum, {apply(target, ctx, args) {return target(...args) * 2}
})
console.log(sum(1, 2)) // 6
console.log(sum.call(null, 1, 2, 3)) // 12
console.log(sum.apply(null, [1, 2, 3])) // 12

construct 拦截 Proxy 实例作为构造函数调用的操作

let User = class {constructor(name) {this.name = name}
}
User = new Proxy(User, {construct(target, args, newTarget) {console.log('construct')  // constructreturn new target(...args)}
})
console.log(new User('xiaoming')) // User {name: "xiaoming"}

【ES6(2015)】Proxy相关推荐

  1. 【ES6(2015)】Module模块

    文章目录 1. 模块化的发展 2. export 3. as 4. export default 5. import 1. 模块化的发展 随着前端的发展,web技术日趋成熟,js功能越来越多,代码量也 ...

  2. 【ES6(2015)】Reflect

    文章目录 1. 设计目的 2. 常用方法 Reflect对象与Proxy对象一样,也是ES6 为了操作对象而提供的新 API. 1. 设计目的 将Object属于语言内部的方法放到Reflect上 l ...

  3. 【ES6(2015)】Iterator

    文章目录 1. 基本语法 2. Iterator 接口与 Generator 函数 MDN : 处理集合中的每个项是很常见的操作.JavaScript 提供了许多迭代集合的方法,从简单的for循环到m ...

  4. 【ES6(2015)】Number

    文章目录 1. 二进制与八进制 2. 新增方法 3. Math扩展 1. 二进制与八进制 ES5 中进制转换: const a = 5 console.log(a.toString(2)) // 转换 ...

  5. 【ES6(2015)】RegExp

    文章目录 1. y修饰符 2. u修饰符 1. y修饰符 ES6为正则表达式添加了y修饰符,叫做"粘连"(sticky)修饰符. y修饰符的作用与g修饰符类似,也是全局匹配,后一次 ...

  6. 【ES6(2015)】String

    文章目录 1. Unicode表示法 2. 遍历器接口 3. 模板字符串 4. 扩展方法 1. Unicode表示法 ES6 加强了对 Unicode 的支持,允许采用\uxxxx形式表示一个字符,其 ...

  7. 【ES6(2015)】Map

    文章目录 1. 基本语法 2. 遍历方式 3. WeekMap ES6 提供了 Map 数据结构.它类似于对象,也是键值对的集合,但是"键"的范围不限于字符串,各种类型的值(包括对 ...

  8. 【ES6(2015)】Set

    文章目录 1. 基本语法 2. 遍历方式 3. WeakSet 在 JavaScript 里通常使用Array或Object来存储数据. 在 ES6 中,新增了数据结构 Set 和 Map,它们分别对 ...

  9. 【ES6(2015)】Symbol

    文章目录 1. 声明方式 2. Symbol.for() 3. Symbol.keyFor() 4. 作为属性名 5. 属性遍历 6. 消除魔术字符串 ES6 引入了一种新的原始数据类型 Symbol ...

最新文章

  1. myeclipse2014新感悟
  2. php5.4curl报错,PHP中使用CURL报错解决方案 rip curl php curl开启 curl下
  3. [vue] 你了解什么是函数式组件吗?
  4. 打败 IE 的葵花宝典:CSS Bug Table
  5. Mysql Cluster集群实现高可用
  6. thymeleaf if 条件判断
  7. 有关于类的定义赋值与调用总结
  8. Atitit.跨语言  文件夹与文件的io操作集合  草案
  9. 云计算机基础架构,云计算基础架构的解决方案
  10. linux xdg open 安装,xdg-open默认应用程序行为
  11. ArcEngine中的ICommand和ITool(转载)
  12. Windows中如何修改Intel网卡的注册表使Wireshark可以抓取802.1q tag包
  13. 【机器学习】五种超参数优化技巧
  14. RLS递归最小二乘法(Recursive Least Squares)
  15. RNA-seq流程学习笔记(18)- Heatmap图
  16. Failed to resolve: com.github.chrisbanes:PhotoView:1.2.6 Show in File Show i
  17. hdu4121 象棋checkmate模拟
  18. 【记录】U盘安装Ubuntu20.04系统
  19. electron环境下,在同一个前端vue界面切换展示不同的flash图片
  20. easypoi读取excel文件异常

热门文章

  1. mybatis使用in语句作为查询条件
  2. Awesomplete 屌爆了
  3. Robots.txt 协议详解及使用说明
  4. C# 文件读取方法,自己写的例子,保存一下,备用
  5. Linux下MySQL 5.5.11编译安装笔记(待验证)
  6. 分享一种中小企业的文件服务器方案
  7. WinDbg+Rotor解析WinForm调用堆栈及实现
  8. 什么才算是“真正的”编程能力?不提升这些能力,你何时能拿高薪!
  9. 在Windows 64位操作系统安装Weblogic的注意事项
  10. 关于数据仓库的架构及3大类组件工具选型