建议先看 Reflect 然后再看 Proxy。该对象用于拦截 JavaScript 操作的方法。
示例代码参考: https://www.javascripttutorial.net/es6/javascript-reflection/
在了解了 Reflect 和 Proxy 之后,还可以再深入了解一下 React.metadata: reflect-metadata
代理是可以实现拦截和自定义的。
示例代码参考: https://www.javascripttutorial.net/es6/javascript-proxy/
实用指南: https://blog.bitsrc.io/a-practical-guide-to-es6-proxy-229079c3c2f0
const axios = require('axios');
const SDK = (options) => {
const client = axios.create(options);
return new Proxy(
{},
{
get: (_, property) => client[property.toLowerCase()]
}
);
};
const client = SDK({
baseURL: 'https://api.xxxx.com',
timeout: 1000,
headers: {
'X-Custom-Header': 'foobar'
}
});
// Use just like axios:
client.get('/xxx').then();
client
.post('/xxx', {
// form body
})
.then();
不规范的使用会导致报错,并且该方式的调用无法被捕获
const p = new Proxy(
{},
{
get: (target, property, receiver) => {
console.log(target, property, receiver);
try {
return property;
} catch (e) {
console.log(e.message);
return '';
}
}
}
);
console.log(p.test);
console.log(p.test());
/*
{} test {}
test
{} test {}
/Users/v0/Projects/Authing/demos/proxy-sdk/index.js:17
console.log(p.test());
^
TypeError: p.test is not a function
at Object. (/Users/v0/Projects/Authing/demos/proxy-sdk/index.js:17:15)
at Module._compile (node:internal/modules/cjs/loader:1101:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:17:47
*/
如果这样写的话:
const p = new Proxy(
{},
{
get: (target, property, receiver) => {
console.log(target, property, receiver);
return () => property;
}
}
);
console.log(p.test);
console.log(p.test());
/*
{} test {}
[Function (anonymous)]
{} test {}
test
*/
虽然不会报错,但是强制了返回为 Function。如果想要更灵活的运用,则不能仅使用空对象进行扩展,需要配合 set
去针对性设置某些 property
。
示例:
const p = new Proxy(
{},
{
construct: (target) => {},
get: (target, property, receiver) => {
console.log(target, property, receiver);
// 注入的方法
if (target.hasOwnProperty(property)) {
return target[property];
}
return () => property;
}
}
);
// 简单的方法之一: 配合 Reflect 使用
Reflect.set(p, 'test', 'test1');
console.log(p.test);
console.log(p.test2());
/*
{ test: 'test1' } test { test: 'test1' }
test1
{ test: 'test1' } test2 { test: 'test1' }
test2
*/
可以配合使用 Reflect Metadata 来注入拦截。比如说创建 Before Hook、 After Hook 等。
// import 'reflect-metadata';
require('reflect-metadata');
const p = new Proxy(
{},
{
construct: (target) => {},
get: (target, property, receiver) => {
const injected = Reflect.getMetadata('before', p, property);
if (injected) injected();
if (target.hasOwnProperty(property)) {
return target[property];
}
return () => property;
}
}
);
Reflect.defineMetadata(
'before',
() => {
console.log('BeforeEach');
},
p,
'test'
);
console.log(p.test());