代理Proxy
用于创建一个对象的代理,实现基本操作的拦截
与自定义
,对外界的访问进行过滤与改写
const p = new Proxy(target,handler)
target:要拦截的目标对象
handler:要拦截的行为
示例
const o = { a: 1, b: 2 }
const p = new Proxy(o, {
get(target, key, receiver) {
console.log(`getting ${key}!`);
return target[key]
}
})
console.log(p.a);
setting a!
1
对象o属性读取的拦截
target可以是一个空对象,那么拦截操作会直接作用在Proxy的实例化对象
1 handler拦截操作
- get()
- set()
- has()
- deleteProperty()
- ownKeys()
- getOwnPropertyDescriptor()
- defineProperty()
- apply()
- getPrototypeOf()
- setPrototypeOf()
- construct()
- isExtensible()
- preventExtensions()
1.1 get(target,key,receiver)
拦截读取
操作
target:目标对象
key:读取的属性名
receiver:Proxy或继承Proxy的对象
const p = new Proxy({}, {
get(target, key, receiver) {
console.log(key);
console.log(target);
console.log(receiver);
return target[key]
}
})
p.a = 2
console.log(p.a);
1.2 set(target,key,value,receiver)
拦截赋值
操作
value:属性要赋于的值
const p = new Proxy({}, {
set(target, key, value, receiver) {
console.log(value);
target[key] = value
},
})
p.a = 2
console.log(p.a);
2
2
可以对设置的值进行判断,再决定是否进行赋值操作
在数据发生变化时,可以自动更新DOM,实现数据绑定
1.3 apply(target,object,args)
拦截函数调用
,call方法、apply方法
target:目标对象(函数)
object:被调用时的上下文对象
args:调用时的参数数组
function sum(num1, num2) {
return num1 + num2
}
const p = new Proxy(sum, {
apply(target, obj, args) {
console.log(obj);
return target(...args)
}
})
console.log(p(2, 3));
p.apply(null, [2, 3])
undefined
5
null
1.4 has(target,key)
拦截in
操作 返回布尔值
const o = { _prop: "私有属性", prop: "foo" }
const p = new Proxy(o, {
has(target, key) {
if (key.startsWith("_")) {
return false
}
return key in target
}
})
console.log("_prop" in p);//false
console.log("prop" in p);//true
对于不可配置的属性,has拦截会报错
for...in循环可以访问到has拦截的属性
1.5 construct(target,args)
拦截new
操作 返回一个对象
function Student(name, age) {
this.name = name;
this.age = age
}
const p = new Proxy(Student, {
construct(target, args) {
console.log("new操作");
return new target(...args)
}
})
const p1 = new p("张三", 18)
console.log(p1);
'new操作'
{name:"张三",age:18}
1.6 deleteProperty(target,key)
拦截delete
操作 返回布尔值
const o = { _prop: "私有属性", prop: "foo" }
const p = new Proxy(o, {
deleteProperty(target, key) {
if (key.startsWith("_")) {
return false
}
return delete target[key]
}
})
console.log(delete p._prop);//false
console.log(delete p.prop);//true
拦截不可配置的属性会报错
1.7 defineProperty(target,key,descriptor)
拦截Object.defineProperty()
,返回布尔值
const p = new Proxy({}, {
defineProperty(target, key, descriptor) {
target[key] = descriptor.value
return true
}
})
Object.defineProperty(p, 'b', {
value: "0"
})
console.log(p.b);//"0"
对象不可扩展时,则不能添加目标对象不存在的属性
不可写与不可配置,不能拦截修改这两个设置
1.8 getOwnPropertyDescriptor(target,key)
拦截Object.getOwnPropertyDescriptor()
,返回属性的描述对象或者undefined
const o = { _prop: "私有属性", prop: "foo" }
const p = new Proxy(o, {
getOwnPropertyDescriptor(target, key) {
if (key.startsWith("_")) {
return undefined
}
return Object.getOwnPropertyDescriptor(target, key)
}
})
console.log(Object.getOwnPropertyDescriptor(p, "_prop"));
console.log(Object.getOwnPropertyDescriptor(p, "prop"));
undefined
{value:"foo",writable:true,enumerable:true,configurable:true}
1.9 getProptypeOf(target)
拦截获取对象原型
的操作,返回一个对象
相关操作
- Object.prototype.__proto__
- Object.prototype.isPrototypeOf()
- Object.getPrototypeOf()
- Reflect.getPrototypeOf()
- instanceof
function Student(name) {
this.name = name
}
const std = new Student("张三")
let n = 1
const p = new Proxy(std, {
getPrototypeOf(target) {
console.log(`拦截获取原型的操作${n++}`);
return Object.getPrototypeOf(target)
}
})
console.log(Object.getPrototypeOf(p) === Student.prototype);
console.log(p instanceof Student);
console.log(Student.prototype.isPrototypeOf(p));
'拦截获取原型的操作1'
true
'拦截获取原型的操作2'
true
'拦截获取原型的操作3'
true
1.10 setPrototypeOf(target,proto)
拦截Object.setPrototypeOf()
,返回布尔值
function Student(name) {
this.name = name
}
const std = new Student("张三")
const p = new Proxy(std, {
setPrototypeOf(target, proto) {
console.log(`拦截设置原型的操作`);
return Object.setPrototypeOf(target, proto)
}
})
Object.setPrototypeOf(p, Object.create(null))
console.log(Object.getPrototypeOf(p));
'拦截设置原型的操作'
{}
不可扩展的对象不能修改原型
1.11 ownKeys(target)
拦截属性名的读取
操作,返回一个数组
相关操作
- Object.getOwnPropertyNames()
- Object.getOwnPropertySymbols()
- Object.keys()
let foo = Symbol("foo")
const o = {
a: 1,
[foo]: "foo"
}
Object.defineProperty(o, "b", {
value: "bar",
enumerable: false
})
let n = 1;
const p = new Proxy(o, {
ownKeys(target) {
console.log(`拦截读取属性名操作${n++}`);
return Reflect.ownKeys(target)
}
})
console.log(Object.keys(p));
console.log(Object.getOwnPropertyNames(p));
console.log(Object.getOwnPropertySymbols(p));
'拦截读取属性名操作1'
['a']
'拦截读取属性名操作2'
['a','b']
'拦截读取属性名操作3'
[Symbol(foo)]
1.12 isExtensible(target)
拦截对象扩展性判断
的操作,返回一个布尔值
相关操作
- Object.isExtensible()
- Object.isFrozen()
- Object.isSealed()
const o = { a: 1 }
Object.seal(o)
const p = new Proxy(o, {
isExtensible(target) {
console.log("拦截");
return Object.isExtensible(target)
}
})
console.log(Object.isExtensible(p));
console.log(Object.isFrozen(p));
console.log(Object.isSealed(p));
'拦截'
false
'拦截'
false
'拦截'
true
1.13 preventExtensions(target)
拦截修改对象扩展性
的操作,返回一个布尔值
相关操作
- Object.preventExtensions()
- Object.seal()
- Object.freeze()
const o1 = { a: 1 }
const o2 = { b: 2 }
const p = new Proxy(o2, {
preventExtensions(target) {
console.log("拦截");
if (target === o1) {
return false
}
return Object.preventExtensions(target)
}
})
Object.preventExtensions(p)
Object.seal(p)
Object.freeze(p)
console.log(Object.isExtensible(p));
拦截
拦截
拦截
false
2 Proxy上的方法与属性
Proxy.revocable(target,handler)
返回一个可取消的Proxy实例
const {proxy,revoke} = Proxy.revocable(target,handler)
proxy:Proxy的实例
revoke:取消代理的方法
const o = { a: 1 }
const { proxy:p, revoke } = Proxy.revocable(o, {})
console.log(p.a);//1
revoke()
console.log(p.a);//TypeError : Revoked
使用场景:目标对象必须通过代理才能访问,访问结束后收回代理权,不允许再次访问
反射Reflect
一个内置对象
,拦截操作,不是一个函数对象,不可构造
所有的属性和方法都是静态的,类似于Math对象
静态方法与Proxy的handler中的操作同名
基本与Object上的方法相同,只有细微上的差别
Reflect的静态方法
- get(target,name,receiver)
- set(target,name,value,receiver)
- has(obj,name)
- deleteProperty(obj,name)
- construct(target,args)
- getPrototypeOf(obj)
- setPrototypeOf(obj,proto)
- apply(func,thisArg,atgs)
- defineProperty(target,key,attr)
- getOwnPropertyDescriptor(target,key)
- isExtensible(target)
- preventExtensions(target)
- ownKeys(target)
1 get set
Object上没有这两个方法
const o = {
a: 1,
get b() {
return this.foo
},
set b(val) {
return this.foo = val
}
}
const b = {
foo: 2
}
console.log(Reflect.set(o, 'a', "1"));//true
console.log(Reflect.get(o, 'a'));//"1"
console.log(Reflect.set(o, 'b', "2", b));//true
console.log(Reflect.get(o, 'b', b));//"2"
给属性部署get与set方法,需要指定绑定的对象receiver
2 has
Reflect.has(obj,name) 等价于 name in obj
3 deleteProperty
Reflect.deleteProperty(obj,name) 等价于 delete obj[name]
4 construct
Reflect.construct(target,args) 等价于 new target(...args)
5 getPrototypeOf setPrototypeOf
Reflect.getPrototypeOf(obj) 等价于Objcet.getPrototype(obj)
前者第一个参数不是对象直接报错,后者会先转化为对象再操作
Reflect.setPrototypeOf(obj,proto) 等价于 Objcet.setPrototypeOf(obj,proto)
前者第一个参数不是对象直接报错,后者返回参数本身
第一个参数为undefined或null,两者都报错
6 apply
Reflect.apply(func,thisArg,args) 等价于 Function.prototype.apply.call(func,thisArg,args) 等价于 func.apply(thisArg,args)
相当先于把Fucntion.prototype.apply 绑定到 func上,thisArg,args作为apply 的参数
由于call绑定后会立即调用,则相当于func.call(thisArgs,args)
7 defineProperty getOwnPropertyDescriptor
Reflect.definProperty(target,key,attr) 等价于 Object.defineProperty(target,key,descriptor)
前者第一个参数不是对象,直接报错
Refeclt.getOwnPropertyDescriptor(target,key) 等价于 Object.getOwnPropertyDescriptor(target,key)
前者第一个参数不是对象报错,后者返回undefined
8 isExtensible preventExtensions
Reflect.isExtensible(target) 等价于 Objcet.isExtensible(target)
非对象,前者报错,后者返回false
Reflect.preventExtensions(target) 等价于 Objcet.prevetExtensions(target)
非对象,前者报错,后者返回原参数
9 ownKeys
Reflect.ownKeys(target) 返回对象的所有属性
等价于 Objcet.getOwnPropertyNames(target)与Objcet.getOwnPropertySymbols(target)的集合
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。