JavaScript Reflect、Proxy
一、Reflect
1、简介
Reflect提供拦截Javascript对象操作的方法,这些方法与处理器对象的方法相对应。Reflect不是一个函数对象,它是不能构造的,它的所有属性和方法都是静态的。
2、方法
Reflect对象提供的静态函数具有和处理器对象(handler)相同的方法名,其中一些方法与Object
对应的方法相同。
-
Reflect.apply()
和
Function.prototype.apply()
类似 -
Reflect.construct()
对构造函数进行
new
操作,相当于执行new target(...args)
-
Reflect.defineProperty()
和
Object.defineProperty()
类似 -
Reflect.deleteProperty()
相当于执行
delete target[name]
-
Reflect.get()
获取对象的某个属性值,相当于执行
target[name]
-
Reflect.set()
给对象属性设置值的函数,返回
Boolean
类型值表示成功与否 -
Reflect.getOwnPropertyDescriptor()
和
Object.getOwnPropertyDescriptor()
类似 -
Reflect.getPrototypeOf()
和
Object.getPrototypeOf()
类似 -
Reflect.setPrototypeOf()
和
Object.setPrototypeOf()
类似 -
Reflect.has()
判断一个对象是否存在某个属性,和
in
运算符功能相同 -
Reflect.isExtensible()
和
Object.isExtensible()
类似 -
Reflect.ownKeys()
返回一个对象的所有自身属性(不包含继函属性)的数组
-
Reflect.preventExtensions()
和
Object.preventExtensions()
类似
二、Proxy
1、简介
Proxy对象通常用于给基本操作定义自定义行为,如:属性查找、赋值、枚举、函数调用等。
- 语法
let p = new Proxy(target, handler);
-
参数
-
target
使用
Proxy
包装的(目标)对象,即需要代理的对象,可以是任何类型的对象,包括原生数组、函数或者是另一个代理对象。 -
handler
使用
handler
定义一些代理函数,当执行代理proxy
对象的操作时会先被handler
的相应函数拦截。
-
2、Handler
Handler(处理器)对象用来自定义代理对象的各种可代理操作,一共有13种可代理操作:
1、apply
拦截函数的调用。要求代理的目标对象(target)必须是可被调用的,即它是一个函数对象。
-
语法
var p = new Proxy(target, { apply: function(target, thisArg, argumentsList){ } });
-
target
目标对象(函数)
-
thisArg
被调用时的上下文对象
-
argumentsList
被调用时的参数数组
-
-
样例
function sum(a, b){
return a + b;
}
const handler = {
apply(target, thisArg, args){
console.log(args);
return target(args[0], args[1]) * 10;
}
};
let proxy = new Proxy(sum, handler);
console.log(sum(1, 2));
console.log('------');
console.log(proxy(1, 2));
2、construct
拦截new
操作符。要求代理的目标对象(target)必须具有Construct
内部方法(即new target
必须是有效的)且必须返回一个对象。
-
语法
var p = new Proxy(target, { construct: function(target, argumentList, newTarget){ } });
-
target
目标对象
-
argumentList
构造函数(constrcutor)的参数列表
-
newTarget
最初被调用的构造函数(即语法定义中的
p
,Proxy对象)
-
-
样例
//怪物 - 性情
function monster(disposition){
this.disposition = disposition;
}
const handler = {
construct(target, args, newTarget){
console.log('call monster constructor');
return new target(...args);
}
};
let proxy = new Proxy(monster, handler);
//fierce: 凶猛的
console.log(new proxy('fierce').disposition);
输出:
call monster constructor
fierce
3、defineProperty
拦截对象的defineProperty
(Object.defineProperty()
、Reflect.defineProperty()
)操作。此方法必须返回Boolean
类型值,表示定义属性是否成功。
-
语法
var p = new Proxy(target, { defineProperty: function(target, property, descriptor){ } });
-
target
目标对象
-
property
要定义或修改的属性名
-
descriptor
将被定义或修改的属性描述符
-
-
样例
let target = {};
let p = new Proxy(target, {
defineProperty(target, prop, descriptor){
console.log(prop, descriptor);
return Reflect.defineProperty(target, prop, descriptor);
}
});
let desc = {
configurable: true,
enumerable: true,
value: 10
};
Object.defineProperty(p, 'a', desc);//a {value: 10, enumerable: true, configurable: true}
console.log(p.a, target.a);//10 10
4、deleteProperty
拦截对象删除属性的操作(delete obj.foo
),返回Boolean
类型值,表示属性是否删除成功。
-
语法
var p = new Proxy(target, { deleteProperty: function(target, property){ } });
-
target
目标对象
-
property
要删除的属性名
-
-
样例
let target = {name: 'albert'};
let p = new Proxy(target, {
deleteProperty(target, prop){
console.log(`delete property: ${prop}`);
return Reflect.deleteProperty(target, prop);
}
});
console.log(p.name);
delete p.name;
console.log(p.name, target.name);
5、get
拦截读取对象属性的操作(proxy.foo
)。
-
语法
var p = new Proxy(target, { get: function(target, property, receiver){ } });
-
target
目标对象
-
property
要获取的属性名
-
receiver
Proxy或继承Proxy的对象
-
-
样例
let target = {name: 'albert'};
let p = new Proxy(target, {
get(target, prop, receiver){
console.log(`get ${prop} value:`);
return Reflect.get(target, prop, receiver);
}
});
p.name;
输出:
get name value:
albert
6、set
拦截设置对象属性的操作(proxy.foo = bar
),返回Boolean
类型值,表示设置属性是否成功。
-
语法
var p = new Proxy(target, { set: function(target, property, value, receiver){ } });
-
property
要设置值的属性名称
-
value
要设置的值
-
-
样例
let target = {};
let p = new Proxy(target, {
set(target, property, value, receiver){
console.log(`set property ${property} = ${value}`);
return Reflect.set(target, property, value, receiver);
}
});
p.name = 'albert';
console.log(target.name, p.name);
输出:
set property name = albert
albert albert
7、getOwnPropertyDescriptor
拦截对象获取自身属性描述的对象,此方法必须返回Object
或undefined
。
-
语法
var p = new Proxy(target, { getOwnPropertyDescriptor(target, prop){ } });
-
target
目标对象
-
prop
需要获取属性描述的属性名
-
-
样例
let target = {name: 'albert'};
let p = new Proxy(target, {
getOwnPropertyDescriptor(target, prop){
console.log(`get ${prop} descriptor`);
return {
configurable: true, enumerable: true, value: 'Tom'
};
}
});
let desc = Object.getOwnPropertyDescriptor(p, 'name');
console.log(desc.value);
输出:
get name descriptor
Tom
8、getPrototypeOf
拦截获取对象原型的操作,该方法必须返回对象或null
。
-
语法
var p = new Proxy(obj, { getPrototypeOf: function(target){ } });
-
样例
let proto = {};
let obj = {name: 'albert'};
let handler = {
getPrototypeOf(target){
console.log(target === obj);//true
console.log(this === handler);//true
return proto;
}
};
let p = new Proxy(obj, handler);
console.log(Object.getPrototypeOf(p) === proto);//true
9、setPrototypeOf
拦截设置对象原型的操作,必须返回Boolean
类型值,表示是否设置成功。
-
语法
var p = new Proxy(target, { setPrototypeOf: function(target, prototype){ } });
-
prototype
对象新原型或
null
-
-
样例
let target = {name: 'ablert'};
let newProto = {name: 'Tom', age: 3};
let p = new Proxy(target, {
setPrototypeOf(target, prototype){
console.log(`set prototype`);
return Reflect.setPrototypeOf(target, prototype);
}
});
Object.setPrototypeOf(p, newProto);
console.log(target.name, target.age);//ablert 3
console.log(p.name, p.age);//ablert 3
10、has
拦截查询对象属性的操作,必须返回Boolean
类型值,表示对象是否拥有该属性。
-
语法
var p = new Proxy(target, { has: function(target, prop){ } });
-
样例
let target = {name: 'Tom', age: 3};
let p = new Proxy(target, {
has(target, prop){
return Reflect.has(target, prop);
}
});
console.log('name' in p);//true
console.log('sex' in p);//false
11、isExtensible
拦截判断对象是否可扩展的操作,返回Boolean
值。
-
语法
var p = new Proxy(target, { isExtensible: function(target){ } });
-
样例
let p = new Proxy({}, {
isExtensible(target){
console.log('isExtensible called');
return 1;
}
});
console.log(Object.isExtensible(p));//true
12、ownKeys
拦截获取对象自身所有属性的操作。
-
语法
var p = new Proxy(target, { ownKeys: function(target){ } });
-
样例
let target = {age: 5};
let p = new Proxy(target, {
ownKeys(target){
console.log('ownKeys called');
return ['a', 'b', 'c'];
}
});
console.log(Object.getOwnPropertyNames(p));//["a", "b", "c"]
13、preventExtensions
拦截将对象变为不可扩展的操作,返回已经不可扩展的对象。
-
语法
var p = new Proxy(target, { preventExtensions: function(target){ } });
-
样例
let target = {age: 5};
let p = new Proxy(target, {
preventExtensions(target){
console.log('preventExtensions');
return Reflect.preventExtensions(target);
}
});
Object.preventExtensions(p);
console.log(Object.isExtensible(target));//false
console.log(Object.isExtensible(p));//false