【ES6(2015)】Proxy
文章目录
- 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相关推荐
- 【ES6(2015)】Module模块
文章目录 1. 模块化的发展 2. export 3. as 4. export default 5. import 1. 模块化的发展 随着前端的发展,web技术日趋成熟,js功能越来越多,代码量也 ...
- 【ES6(2015)】Reflect
文章目录 1. 设计目的 2. 常用方法 Reflect对象与Proxy对象一样,也是ES6 为了操作对象而提供的新 API. 1. 设计目的 将Object属于语言内部的方法放到Reflect上 l ...
- 【ES6(2015)】Iterator
文章目录 1. 基本语法 2. Iterator 接口与 Generator 函数 MDN : 处理集合中的每个项是很常见的操作.JavaScript 提供了许多迭代集合的方法,从简单的for循环到m ...
- 【ES6(2015)】Number
文章目录 1. 二进制与八进制 2. 新增方法 3. Math扩展 1. 二进制与八进制 ES5 中进制转换: const a = 5 console.log(a.toString(2)) // 转换 ...
- 【ES6(2015)】RegExp
文章目录 1. y修饰符 2. u修饰符 1. y修饰符 ES6为正则表达式添加了y修饰符,叫做"粘连"(sticky)修饰符. y修饰符的作用与g修饰符类似,也是全局匹配,后一次 ...
- 【ES6(2015)】String
文章目录 1. Unicode表示法 2. 遍历器接口 3. 模板字符串 4. 扩展方法 1. Unicode表示法 ES6 加强了对 Unicode 的支持,允许采用\uxxxx形式表示一个字符,其 ...
- 【ES6(2015)】Map
文章目录 1. 基本语法 2. 遍历方式 3. WeekMap ES6 提供了 Map 数据结构.它类似于对象,也是键值对的集合,但是"键"的范围不限于字符串,各种类型的值(包括对 ...
- 【ES6(2015)】Set
文章目录 1. 基本语法 2. 遍历方式 3. WeakSet 在 JavaScript 里通常使用Array或Object来存储数据. 在 ES6 中,新增了数据结构 Set 和 Map,它们分别对 ...
- 【ES6(2015)】Symbol
文章目录 1. 声明方式 2. Symbol.for() 3. Symbol.keyFor() 4. 作为属性名 5. 属性遍历 6. 消除魔术字符串 ES6 引入了一种新的原始数据类型 Symbol ...
最新文章
- myeclipse2014新感悟
- php5.4curl报错,PHP中使用CURL报错解决方案 rip curl php curl开启 curl下
- [vue] 你了解什么是函数式组件吗?
- 打败 IE 的葵花宝典:CSS Bug Table
- Mysql Cluster集群实现高可用
- thymeleaf if 条件判断
- 有关于类的定义赋值与调用总结
- Atitit.跨语言 文件夹与文件的io操作集合 草案
- 云计算机基础架构,云计算基础架构的解决方案
- linux xdg open 安装,xdg-open默认应用程序行为
- ArcEngine中的ICommand和ITool(转载)
- Windows中如何修改Intel网卡的注册表使Wireshark可以抓取802.1q tag包
- 【机器学习】五种超参数优化技巧
- RLS递归最小二乘法(Recursive Least Squares)
- RNA-seq流程学习笔记(18)- Heatmap图
- Failed to resolve: com.github.chrisbanes:PhotoView:1.2.6 Show in File Show i
- hdu4121 象棋checkmate模拟
- 【记录】U盘安装Ubuntu20.04系统
- electron环境下,在同一个前端vue界面切换展示不同的flash图片
- easypoi读取excel文件异常
热门文章
- mybatis使用in语句作为查询条件
- Awesomplete 屌爆了
- Robots.txt 协议详解及使用说明
- C# 文件读取方法,自己写的例子,保存一下,备用
- Linux下MySQL 5.5.11编译安装笔记(待验证)
- 分享一种中小企业的文件服务器方案
- WinDbg+Rotor解析WinForm调用堆栈及实现
- 什么才算是“真正的”编程能力?不提升这些能力,你何时能拿高薪!
- 在Windows 64位操作系统安装Weblogic的注意事项
- 关于数据仓库的架构及3大类组件工具选型