最近公司在组织前端团队学习JavaScript高级程序设计(第四版)。这两天把第九章看完了,以下是精简版的学习笔记:
本章要点:
- proxy是代理的意思, 可以通过 构造函数 Proxy,给目标对象targetObj创建一个代理对象
- 对代理对象执行操作,会走handler里的方法,对源对象执行操作,不会
- 代理可以捕获13中不同的基础api,handler中可定义多个捕获方法
- 是一个全局的Reflect对象,所有捕获的方法都有对应的Reflect api方法。它与捕获器拦截的方法同名、行为相同。
- Reflect api 不限于捕获处理程序handler,也可用在处理普通对象上
- 大多数Reflect api在Object上有对应的方法
- 有了Reflect后,可以方便写捕获器
- 代理模式的几种应用
proxy
what?(Proxy是什么?)
proxy是代理的意思, 可以通过 构造函数 Proxy,给目标对象targetObj创建一个代理对象。
const proxyObj = new Proxy(targetObj, handlerObj)
可以给对象obj创建一个代理。
why?(为什么用Proxy?)
当对代理对象进行一些对象操作时,会先执行代理中handlerObj对象定义的方法。
比如:
get( ) // 取对象属性
set( ) // 往对象中添加属性
how?(怎么用Proxy?)
对代理对象执行操作,会走handler里的方法
对源对象执行操作,不会走handler里的方法
const target = {foo: "bar"}
const handler = {
get(target, prop, receiver){ // get()是一个捕获器,其参数分别代表:目标对象、目标属性、代理对象。每个捕获器入参不同。
return "handle override"
}
}
const proxyObj = new Proxy(target,handler)
console.log(proxyObj.foo) // "handle override",执行handler
console.log(target.foo) // "bar",没有执行handler
Reflect
what?(Reflect是什么?)
是一个全局的Reflect对象,所有捕获的方法都有对应的Reflect api方法。它与捕获器拦截的方法同名、行为相同。
Reflect api 不限于捕获处理程序handler
大多数Reflect api在Object上有对应的方法。
why?(为什么用Reflect?)
有了Reflect后,可以方便写捕获器。
看例子:
const target = {foo: "bar"}
const handler = {
get(target, prop, receiver){
return Reflect.get(...arguments)
}
}
const proxyObj = new Proxy(target,handler)
Reflect api会提供一些状态标记。
Reflect.set() ,Reflect.defineProperty()会返回布尔值。
Reflect api可利用一等函数替换操作符。Reflect.has( )
const obj = {name: "cc"}
const target = Object.create(obj)
target.age = 12
if(Reflect.has(target, "name")) { // 亲测和对象的in操作符效果相同,都可以获取对象原型链上的属性
console.log("wow, I have!")
}
how?(怎么用Reflect?)
以上,写捕获器的时候可以用,利用它的返回值,在对象上也可以用
代理捕获器和对应的反射方法
代理可以捕获13中不同的基础api。
get() 获取属性时
set() 设置属性值
has() 对象执行in操作时
defineProperty( )
getOwnPropertyDescriptor()
deleteProperty()
ownKeys()
getPrototypeOf()
setPropotypeOf()
isExtensible()
preentExtensions()
apply()
construct()
代理模式的几种应用
- 跟踪属性访问
通过捕获get、set 和has 等操作,可以知道对象属性什么时候被访问、被查询。
- 隐藏属性
- 属性验证
set()里面写捕获器,验证对象的赋值操作是否合法
例子:
setObjDataEmpty = (paramObj) => {
const proxy = new Proxy(paramObj, {
set(target, prop) {
const oldVal = target[prop]
if(typeof oldVal === "string") { // 字符串,直接赋值
return Reflect.set(...arguments)
}else if(Array.isArray(oldVal)){
return Reflect.set(target, prop, []) // 数组,置空
}else{
return false // 都不是,赋值失败
}
}
})
Object.keys(proxy).forEach(key => {
proxy[key] = ""
})
return proxy
}
- 函数和构造函数的参数验证
consructor = () => {
class SetId {
constructor(id) {
this.id = id
}
}
const pSetId = new Proxy(SetId, {
construct(target, argumentList) {
if(argumentList[0] === undefined) {
throw("oh, you must put id!")
}else{
return Reflect.construct(...arguments)
}
}
})
const id1 = new pSetId("1")
console.log(id1) // {id: '1'}
const id2 = new pSetId() // Uncaught oh, you must put id!
console.log(id2)
}
- 数据绑定与可观察对象
const userList = [];
class User {
constructor(name) {
this.name = name;
}
}
const proxy = new Proxy(User, {
construct() {
const newUser = Reflect.construct(...arguments);
userList.push(newUser);
return newUser;
}
});
new proxy('John');
new proxy('Jacob');
new proxy('Jingleheimerschmidt');
console.log(userList);