共计 6964 个字符,预计需要花费 18 分钟才能阅读完成。
代理 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)的汇合