Open soraping opened 5 years ago
Reflect.defineProperty( (target && target.prototype) || target, propertyKey, descriptor );
(target && target.prototype) || target, 这里为啥要这么判断呢?
很久没有写js了,看着都有点陌生了。。。
这段判断是我加的,一般情况下只有 target
便就够了,我也是通过各种调试发现,真正需要的是 target .prototype
,具体当时为什么这么做我还真忘记了,你也可以dubug,断点试下,打印上下文参数,应该不难发现
之前写过的一篇关于《前端
IOC
的简单实践》,基于本人是一个前端,设计模式的基础知识都不完备,所以内容不是太严谨,正在学习中! 文章中提到了一个关键词:依赖注入。有小伙伴跟我提说在真实项目中如何使用的,我知道
angular
就是借鉴spring
的ioc
,奈何我没有用过,下面呢就来说说我之前在nodejs
项目上的一些实践。去年,我贴了一个
nodejs
的简易web框架-- lenneth,基于koa2
搞的,简单说就是用装饰器模仿spring
来写nodejs
的注解(说注解习惯了,就不说装饰器了),看下示例:看到这些注解,是不是很眼熟,就是从
spring
抄来的,具体介绍可以去项目里看看,下面来重点介绍实现Autowired
注解的过程,也就是依赖注入的实践。看上面的实例,这个项目依赖了一个
UserService
类,在这个UserController
这个方法中会用到这个依赖类的某个方法。依赖注入:
使用:
来看下
Autowired
注解的实现:解读这段实现之前,先引出了另一个概念--反射,就是在运行时动态获取一个对象的一切信息,包括方法/属性等等,特点在于动态类型反推导。
Reflect
是ES6新增的api,本身提供了不少静态方法,不过要使用还需要引入reflect-metadata
这个库,为了使编译器在设计时将元数据序列化传给修饰器。通过反射能获得系统提供的
metadataKey
信息:design:type
修饰目标对象的类型;design:paramtypes
修饰目标对象方法的参数类型;design:returntype
修饰目标对象方法返回值的类型;来看下案例:
控制台展示:
特别注意:
design:returntype
依赖于所修饰方法的是否显式定义类型了,如果没有定义类型,那就会默认返回undefined
。我们也可以自定义
metadataKey
,即在相应的类上定义自定义的元数据。自此,有了这个知识,在看上面的
Autowired
代码是不是简单的多了。Autowired
注解的本质是一个属性修饰器,主要是考虑到会有参数传入,所以就写了一个高阶函数。修饰器本身就不做介绍了,可以看下阮一峰老师的es6教程。在方法内部,先获取了被修饰对象的类型,转换如下:
这个
metadataKey
是系统提供的design:type
,获取被修饰对象的类型。那这个
typeClass
的值就是UserService
。这里就是获取
UserController
的userService
属性的描述对象,那这个值有什么用呢?Reflect.getOwnPropertyDescriptor
方法其实等同于Object.getOwnPropertyDescriptor
,它会返回一个object:返回的四个字段中
value
就是这个属性的值,我们只要修改这个value
字段,就可以实现注入了。所以,最后修改了这个属性的描述对象的值,使它指向了所返回类型的实例对象,再重新定义这个属性的描述对象,这样编译后,
userService
这个被修饰的属性就是UserService
的实例对象,能够访问到UserService
内的属性方法了。如此,就实现了
Autowired
注解的功能了。完整示例: