鸿蒙反射实践指南
Reflect 对象提供了多种方法来封装和操作JavaScript对象的行为。详见源码,下面给出使用示例。Reflect.get(target, propertyKey[, receiver])获取目标对象的属性值。console.log(value) // 输出 1Reflect.set(target, propertyKey, value[, receiver])设置目标对象的属性值。cons
Reflect是ECMAScript 6(ES6)引入的一个内置对象,它提供了封装普通JavaScript对象原生行为的方法。与普通的函数不同,Reflect方法通常与Proxy对象一起使用,以实现对对象操作的拦截和定制。
Reflect基本介绍
Reflect 对象提供了多种方法来封装和操作JavaScript对象的行为。详见源码,下面给出使用示例。
-
Reflect.get(target, propertyKey[, receiver])获取目标对象的属性值。
const obj = { a: 1, b: 2 } const value = Reflect.get(obj, 'a') console.log(value) // 输出 1 -
Reflect.set(target, propertyKey, value[, receiver])设置目标对象的属性值。
const obj = { a: 1 } const result = Reflect.set(obj, 'a', 2) console.log(result) // 输出 true console.log(obj.a) // 输出 2 -
Reflect.has(target, propertyKey)检查目标对象是否有某个属性。
const obj = { a: 1 } const hasProp = Reflect.has(obj, 'a') console.log(hasProp) // 输出 true -
Reflect.deleteProperty(target, propertyKey)删除目标对象的属性。
const obj = { a: 1 } const result = Reflect.deleteProperty(obj, 'a') console.log(result) // 输出 true console.log(obj.a) // 输出 undefined -
Reflect.ownKeys(target)返回目标对象的所有自身属性键。
const obj = { a: 1, b: 2 } const keys = Reflect.ownKeys(obj) console.log(keys) // 输出 ['a', 'b'] -
Reflect.getPrototypeOf(target)获取目标对象的原型。
const obj = Object.create({ a: 1 }) const proto = Reflect.getPrototypeOf(obj) console.log(proto) // 输出 { a: 1 } -
Reflect.setPrototypeOf(target, prototype)设置目标对象的原型。
const obj = {} const proto = { a: 1 } const result = Reflect.setPrototypeOf(obj, proto) console.log(result) // 输出 true console.log(obj.a) // 输出 1 -
Reflect.isExtensible(target)检查目标对象是否可扩展。
const obj = {} const extensible = Reflect.isExtensible(obj) console.log(extensible) // 输出 true -
Reflect.preventExtensions(target)阻止目标对象扩展。
const obj = {} const result = Reflect.preventExtensions(obj) console.log(result) // 输出 true try { Reflect.defineProperty(obj, 'a', { value: 1 }) } catch (e) { console.log(e) // 抛出错误 } -
Reflect.getOwnPropertyDescriptor(target, propertyKey)获取目标对象的属性描述符。
const obj = { a: 1 } const desc = Reflect.getOwnPropertyDescriptor(obj, 'a') console.log(desc) // 输出 { value: 1, writable: true, enumerable: true, configurable: true } -
Reflect.defineProperty(target, propertyKey, attributes)定义或修改目标对象的属性。
const obj = {} const result = Reflect.defineProperty(obj, 'a', { value: 1, writable: false }) console.log(result) // 输出 true console.log(obj.a) // 输出 -
Reflect.apply(function, thisArg, argArray)调用函数,传入特定的 this 值和参数。
const add = (a, b) => a + b const result = Reflect.apply(add, null, [1, 2]) console.log(result) // 输出 3 -
Reflect.construct(constructor, argumentsList[, newTarget])创建并初始化一个新对象。
function Person(name) { this.name = name } const person = Reflect.construct(Person, ['John']) console.log(person.name) // 输出 "John" -
Reflect.hasOwn(target, propertyKey)检查目标对象是否具有指定的自身属性。
const obj = { a: 1 } const hasOwnProp = Reflect.hasOwn(obj, 'a') console.log(hasOwnProp) // 输出 true
Reflect与Proxy
Proxy和Reflect 经常配合使用,以实现对对象操作的拦截和自定义行为。Proxy允许你创建一个对象的代理,这个代理可以拦截并控制对目标对象的各种操作,如属性读取、赋值、枚举、函数调用等。而Reflect提供了一系列与Proxy的陷阱(traps)相对应的静态方法,使得我们可以直接使用标准的语法来执行这些操作。
class Data{
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
class DataProxyHandler implements ProxyHandler<Data>{
get(target: Data, p: PropertyKey, receiver: any): any {
console.log(`getting ${String(p)}`)
return Reflect.get(target, p, receiver)
}
set(target: Data, p: PropertyKey, value: any, receiver: any): boolean {
console.log(`setting ${String(p)} = ${value}`)
return Reflect.set(target, p, value, receiver)
}
}
let proxy = new Proxy(new Data('zhangsan', 18), new DataProxyHandler())
proxy.age = 20
console.log(proxy.age)
Reflect 和Metadata
Reflect Metadata 是 ES7 的一个提案,它主要用来在声明的时候添加和读取元数据。TypeScript 在 1.5+的版本已经支持它,你只需要:
npm i reflect-metadata --save- 在
tsconfig.json里配置emitDecoratorMetadata选项。
Reflect允许在类或其成员上附加元数据,这可以通过装饰器实现。
-
Reflect.metadata(metadataKey, metadataValue):这是一个装饰器工厂,可以用来自定义元数据。
-
Reflect.getMetadata(metadataKey, target[, propertyKey]):获取继承链上的元数据。
function metadata(metadataKey: any, metadataValue: any): { (target: Function): void (target: Object, propertyKey: string | symbol): void } import "reflect-metadata" @Reflect.metadata('inClass', 'A') class Test { @Reflect.metadata('inMethod', 'B') public hello(): string { return 'hello world' } } console.log(Reflect.getMetadata('inClass', Test)) // 'A' console.log(Reflect.getMetadata('inMethod', new Test(), 'hello')) // 'B' function Prop(): PropertyDecorator { return (target, key: string | symbol) => { const type = Reflect.getMetadata('design:type', target, key) console.log(`type: ${type.name}`) // type: string } } class SomeClass { @Prop() public Aprop!: string; } -
Reflect.defineMetadata(metadataKey, metadataValue, target[, propertyKey]):定义元数据。
function classDecorator(): ClassDecorator{ return (target) => { Reflect.defineMetadata("classMetadata", "a", target) } } function methodDecorator(): MethodDecorator{ return (target, key: string | symbol, descriptor: PropertyDescriptor) => { Reflect.defineMetadata("methodMetadata", "b", target, key) } } @classDecorator() class SomeClass { @methodDecorator() someMethod() { } } -
Reflect.getOwnMetadata(metadataKey, target[, propertyKey]):获取指定的元数据。
-
Reflect.deleteMetadata(metadataKey, target[, propertyKey]):删除元数据。
控制反转与依赖注入
const Injectable = (): ClassDecorator => target => {}
- const Injectable =:声明一个常量 Injectable。
- (): ClassDecorator:这部分表示 Injectable 是一个函数,它不接受参数(空括号),并返回一个 ClassDecorator 类型。
- => target => {}:这是一个箭头函数,它返回另一个箭头函数。
- 外层箭头函数 () => 对应 Injectable 函数本身。
- 内层箭头函数 target => {} 是实际的类装饰器。
- target:这是类装饰器的参数,表示被装饰的类的构造函数。
- {}:装饰器的函数体,目前是空的。
完整解释:Injectable 是一个函数,当被调用时(如 @Injectable()),它会返回一个类装饰器。这个类装饰器是一个接受 target(被装饰的类)作为参数的函数。
type Constructor<T = any> = new (...args: any[]) => T
class OtherServie{
a = 1
}
@Inject()
class TestService {
constructor(public readonly other: OtherServie) { }
testMethod() {
console.log(this.other.a)
}
}
const Factory = <T>(target: Constructor<T>): T => {
// 获取所有注入的服务
const providers = Reflect.getMetadata('design:paramtypes', target)
const args = providers.map((provider: Constructor) => new provider())
return new target(...args)
}
Factory(TestService).testMethod()
Controller与Get
const METHOD_METADATA = 'method'
const PATH_METADATA = 'path'
const Controller = (path: string): ClassDecorator => {
return target => {
Reflect.defineMetadata(PATH_METADATA, path, target)
}
}
const createMappingDecorator = (method: string) => (path: string): MethodDecorator => {
return (target, key, descriptor) => {
if (descriptor.value) {
Reflect.defineMetadata(PATH_METADATA, path, descriptor.value)
Reflect.defineMetadata(METHOD_METADATA, method, descriptor.value)
}
}
}
const Get = createMappingDecorator('GET')
const Post = createMappingDecorator('POST')
function mapRoute(instance: Object) {
const prototype = Object.getPrototypeOf(instance)
// 筛选出类的 methodName
const methodsNames = Object.getOwnPropertyNames(prototype).filter(item => item !== 'constructor' && typeof prototype[item] === 'function')
return methodsNames.map(methodName => {
const fn = prototype[methodName]
// 取出定义的 metadata
const path = Reflect.getMetadata(PATH_METADATA, fn)
const method = Reflect.getMetadata(METHOD_METADATA, fn)
return {
fn,
path,
method,
methodName
}
})
}
@Controller('/test')
class SomeClass {
@Get('/a')
someGetMethod() {
return 'hello world'
}
@Post('/b')
somePostMethod() {}
}
Reflect.getMetadata(PATH_METADATA, SomeClass) // '/test'
console.log(mapRoute(new SomeClass()))
/**
* [
{
fn: [Function: someGetMethod],
path: '/a',
method: 'GET',
methodName: 'someGetMethod'
},
{
fn: [Function: somePostMethod],
path: '/b',
method: 'POST',
methodName: 'somePostMethod'
}
]
*/
更多推荐



所有评论(0)