ES6版本增加Proxy构造函数对象和Reflect对象,本文进行梳理和总结。
代理捕获器 | 拦截操作 | 示例 |
defineProperty(target, property, descriptor) | Object.defineProperty(proxy, property, descriptor) Reflect.defineProperty(proxy, property, descriptor) |
const target = {}; const proxy = new Proxy( target, defineProperty(target, property, descriptor) { return Reflect.defineProperty(...arguments) } ) Object.defineProperty(proxy, 'foo', { value: 1, }) // defineProperty() |
deleteProperty(target, prproperty) | delete proxy.property delete proxy[property] Reflect.deleteProperty(proxy, property) |
const target = {}; const proxy = new Proxy( target, deleteProperty(target, property, descriptor) { return Reflect.deleteProperty(...arguments) } ) delete proxy.foo // deleteProperty(() |
getOwnPropertyDescriptor(target, property) | Object.getOwnPropertyDescriptor(proxy, property) Reflect.getOwnPropertyDescriptor(proxy, property) |
onst target = {}; const proxy = new Proxy( target, getOwnPropertyDescriptor(target, property) { return Reflect.getOwnPropertyDescriptor(...arguments) } ) Object.getOwnPropertyDescriptor(proxy, 'foo') // getOwnPropertyDescriptor() |
get(target, propertyKey, receiver?) | proxy.property proxy[property] Object.create(proxy)[property] Reflect.get(proxy, property, receiver) |
const target = {}; const proxy = new Proxy( target, get(target, property, receiver) { return Reflect.get(...arguments) } ) proxy.foo // get() |
set(target, property, value, receiver?) | proxy.property = value proxy[property] = value Object.create(proxy)[property] = value Reflect.set(proxy, proerpty, value, receiver) |
const target = {}; const proxy = new Proxy( target, set(target, property, receiver) { return Reflect.get(...arguments) } ) proxy.foo = 1 // set() |
has(target, property) | property in proxy property in Object.create(proxy) with(proxy) { (property); } Reflect.has(proxy, property) |
const target = {}; const proxy = new Proxy( target, has(target, property) { return Reflect.has(...arguments) } ) 'foo' in proxy // has() |
getPrototypeOf(target) | Object.getPrototypeOf(proxy) Reflect.getPrototypeOf(proxy) proxy.__proto__ Object.prototype.isPrototypeOf(proxy) proxy instanceof Object |
const target = {}; const proxy = new Proxy( target, getPrototypeOf(target) { return Reflect.getPrototypeOf(...arguments) } ) Object.getPrototypeOf(proxy) // gePrototypeOf() |
setPrototypeOf(target, prototype) | Object.setPrototypeOf(proxy, ?) Reflect.setPrototypeOf(proxy, ?) |
const target = {}; const proxy = new Proxy( target, setPrototypeOf(target, prototype) { return Reflect.setPrototypeOf(...arguments) } ) Object.setPrototypeOf(proxy, Object) // setPrototypeOf() |
apply(target, thisArg, argsList) |
proxy(...argsList) Function.prototype.apply(thisArg, argsList) Function.prototype.call(thisArg, ...argsList) Reflect.apply(target, thisArg, argsList) |
const target = () => {}; const proxy = new Proxy( target, apply(target, thisArg, argsList) { return Reflect.apply(...arguments) } ) proxy(); // apply() |
construct(target, argsList, newTarget?) | new Proxy(...argsList) Reflect.contruct(target, argsList, newTarget) |
const target = function() {}; const proxy = new Proxy( target, construct(target, argsList, newTarget) { return Reflect.construct(...arguments) } ) new proxy(); // construct() |
ownKeys(target) | Object.getOwnPropertyNames(proxy) Object.getOwnPropertySymbols(proxy) Object.keys(proxy) Reflect.ownKeys(proxy) |
const target = {}; const proxy = new Proxy( target, ownKeys(target) { return Reflect.ownKeys(...arguments) } ) Object.keys(proxy) // ownKeys() |
isExtensible(target) | Object.isExtensible(proxy) Reflect.isExtensible(proxy) |
const target = {}; const proxy = new Proxy( target, isExtensible(target) { return Reflect.isExtensible(...arguments) } ) Object.isExtensible(proxy) // isExtensible() |
preventExtensions(target) | Object.preventExtensions(proxy) Reflect.preventExtensions(proxy) |
const target = {}; const proxy = new Proxy( target, preventExtensions(target) { return Reflect.preventExtensions(...arguments) } ) Object.preventExtensions(proxy) // preventExtensions() |
Reflect静态方法比Object静态方法的优势是:方法执行出错时,不会抛出错误,而是返回false。
Reflect静态方法 | 说明 | 示例 |
Reflect.defineProperty(target, property, descriptor) | 功能:基本等同于Object.defineProperty(),不同的Reflect是返回boolean值,Object是返回一个对象 输入:Object, any, Object 输出:boolean(即true } false) |
let obj = {}; Reflect.defineProperty(obj, 'x', { value: 7 }); // 返回true obj.x 得到7 |
Reflect.deleteProperty(target, prproperty) | 功能:替代delete操作符,属性不存在会返回true,属性不可配置返回false 输入:Object | Array 输出:boolean(即true } false) |
Reflect.deleteProperty({}, 'foo') 得到true Reflect.deleteProperty(Object.freeze({ foo: 1 }), 'foo') 得到false |
Reflect.getOwnPropertyDescriptor(target, property) | 功能: 返回目标对象指定property属性的描述符,Object.getOwnPropertyDescriptor相似,但target不是对象类型时,Object上的会强制类型转换,Reflect上的会抛出TypeError 输入:Object, any 输出:propertyDescriptor | undefined |
Reflect.getOwnPropertyDescriptor({ x: 'hello' }, 'x') 得到 {value: 'hello', writable: true, enumerable: true, configurable: true} |
Reflect.get(target, propertyKey, receiver?) | 功能:获取target的property属性的值,与target[propertyKey]相似,替换对象属性访问操作符,如果target定义了getter,receiver是getter调用时的this值 输入:Object | Array, any, thisObject? 输出:any |
obj = {a: 1, b: '123'}; Reflect.get(obj, a) 得到1 |
Reflect.set(target, property, value, receiver?) | 功能:设置target的property属性值为value,替换=赋值操作符,如果target定义了setter,receiver是setter调用时的this值 输入:Object | Array, any, any, thisObject? 输出:boolean(即true } false) |
obj = {a: 1, b: '123'}; Reflect.set(obj, c, true) 得到true obj变成 {a: 1, b: '123', c: true}; |
Reflect.has(target, property) | 功能:替代in操作时或with(),检查目标对象是否存在此属性 输入:Object, any 输出:输出:boolean(即true } false) |
Reflect({ x: 0 }, 'x') 得到true |
Reflect.getPrototypeOf(target) | 功能:与Object.getPrototypeOf()相似,但target不是对象类型时,Object上的会强制类型转换,Reflect上的会抛出TypeError,返回指定对象的原型对象 输入:Object 输出:Object | null |
Reflect.getPrototypeOf({}) 得到Object.prototype |
Reflect.setPrototypeOf(target, prototype) | 功能:与Object.setPrototypeOf()相似,设置对象的原型,即修改对象__proto__指向 输入: 输出:输出:boolean(即true } false) |
const obj1 = {}; Reflect.setPrototypeOf(obj1, Object.prototype); 得到true 且 obj1.__proto__指向Object.prototype |
Reflect.apply(target, thisArg, argsList) |
功能:对一个函数对象进行调用操作,同时可传入数组作为调用参数,用于替换Function.prototype.apply.call(Math.floor, undefined, [1.75]); 输入:Function, thisObject, Array 输出:target执行结果 |
Reflect.apply(Math.floor, undefined, [1.75]) 下取整得到1 Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111]),); 通过Unicode码得到字符串'hello' Reflect.apply(RegExp.prototype.exec, /ab/, ['confabulation']).index; 相当于/ab/.exec('confabulation') 得到4 |
Reflect.construct(target, argsList, newTarget?) | 功能:替代new操作符,如果newTarget存在,则相当于 obj=Object.create(newTarget.prototype) target.apply(obj, argsList) 输入:Funtion, Array 输出:实例化对象 |
function Foo() { } let obj = new Foo(...args) obj = Reflect.contruct(Foo, args) |
Reflect.ownKeys(target) | 输入:类似于Object.keys(),但不受enumerable影响,等同于Object.getOwnPropertyNames(target)和Object.getOwnPropertySymbols(target)返回数组的concat结果,返回目标对象自身属性键组成的数组 输出:Array |
sym = Symbol.for('comet'); obj = { a: 1, b: '123', [sym]: true } Reflect.ownKeys(obj); 得到['a', 'b', Symbol(comet)] |
Reflect.isExtensible(target) | 功能:判断一个对象是否可以扩展(即是否可以添加新属性),与Object.isExtensible()相似,但target不是对象类型时,Object上的会强制类型转换,Reflect上的会抛出TypeError 输入:Object 输出:boolean(即true } false) |
Reflect.isExtensible(Object.seal({})) 得到false Reflect.isExtensible(Object.freeze({})) 同样得到false |
Reflect.preventExtensions(target) | 功能:阻止目标对象扩展,与Object.preventExtensions()相似,但target不是对象类型时,Object上的会强制类型转换,Reflect上的会抛出TypeError 输入:Obejct 输出:boolean(即true } false) |
empty = {} Reflect.preventExtensions(empty) 返回true |
const user = {
name: 'Jake',
};
const proxy = new Proxy(
user,
{
get(target, property, receive) {
console.log(`Getting ${property}`);
return Reflect.get(...arguments);
},
set(target, property, value, receive) {
console.log(`Setting ${property}=${value}`);
return Reflect.set(...arguments);
}
}
);
proxy.name; // Getting name
proxy.age = 27; // Setting age=27
const hiddenProperties = ['foo', 'bar'];
const targetObject = {
foo: 1,
bar: 2,
baz: 3
};
const proxy = new Proxy(
targetObject,
{
get(target, property, receive) {
if(hiddenProperties.includes(property)) {
return undefined
} else {
return Reflect.get(...arguments);
}
},
has(target, property) {
if(hiddenProperties.includes(property)) {
return false;
} else {
return Reflect.set(...arguments);
}
}
}
)
console.log(proxy.foo); // undefined
console.log(proxy.bar); // undefined
console.log(proxy.baz); // 3
console.log('foo' in proxy); // false;
console.log('bar' in proxy); // false
console.log('baz' in proxy) // true;
const target = {
onlyNumberGoHere: 0
};
const proxy = new Proxy(
target,
{
set(target, property, value) {
if(typeof value !== 'number') {
return false;
} else {
return Reflect.set(...arguments);
}
}
}
);
proxy.onlyNumberGoHere = 1;
console.log(proxy.onlyNumberGoHere); // 1
proxy.onlyNumberGoHere = '2';
console.log(proxy.onlyNumberGoHere); // 1
function median(...nums) {
return nums.sort()[Math.floor(nums.length / 2)];
}
const proxy = new Proxy(
median,
{
apply(target, thisArg, argsList) {
for(const arg of argsList) {
if(typeof arg !== 'number') {
throw 'Non-number argument provided';
}
}
return Reflect.apply(...arguments);
}
}
)
console.log(proxy(4, 7, 1)); // 4
console.log(proxy(4, '7', 1)); // Error: Non-number argument provided
class User {
constructor(id) {
this.id_ = id;
}
}
const proxy = new Proxy(
User,
{
construct(target, argsList, newTarget) {
if(argsList[0] === undefined) {
throw 'User cannot be instantiated without id';
} else {
return Reflect.construct(...arguments);
}
}
}
)
new proxy(1);
new proxy(); // Error: User cannot be instantiated without id
const userList = [];
class User {
constructor(name) {
this.name_ = name;
}
}
const proxy = new Proxy(
User,
{
construct() {
const newUser = Reflect.construct(...arguments);
// 新实例化对象全部push到数组中
userList.push(newUser);
return newUser;
}
}
)
new proxy('John');
new proxy('Jacob');
new proxy('Jingleheimerschmidt');
onsole.log(userList); // [User {}, User {}, User{}]
function emit(newValue) {
console.log(newValue);
}
const proxy = new Proxy(
userList,
{
set(target, property, value, receiver) {
const result = Reflect.set(...arguments);
if(result) {
// 每次更新target的property属性的值,成功后,则emit掉
emit(Reflect.get(target, property, receiver));
}
return result;
}
}
)
proxy.push('John');
// John
proxy.push('Jacob');
// Jacob
下一篇:【ECMAScript】Object对象的属性和方法梳理和总结(第八篇)-CSDN博客
注:以上,如有不合理之处,还请帮忙指出,大家一起交流学习~