从源码角度深入解析Angular @Injectable注解的核心工作原理
正文
首先,让我们观察两个来自 SAP 电商云 Spartacus UI 的 Angular 服务类。这两个类都添加了 @Injectable 装饰器,唯一的区别在于是否包含 providedIn 参数:


@Injectable() 装饰器
@Injectable() 装饰器的作用非常明确——它告诉 Angular:这个类可以被纳入依赖注入系统。换句话说,这是让服务具备“可注入”能力的关键入口。
如果加上 providedIn: 'root',就表示该服务在整个应用范围内都是可见的,任何组件或其他服务都可以直接请求它,而无需在模块中手动注册。
那么,当我们在组件中需要使用某个服务时,Angular 是如何知道要注入哪个实例的呢?答案隐藏在构造函数的参数类型里。来看一个典型例子:
import { Component } from '@angular/core';
import { Http } from '@angular/http';
@Component({
selector: 'example-component',
template: 'I am a component
'
})
class ExampleComponent {
constructor(private http: Http) {
// use `this.http` which is the Http provider
}
}
这里 private http: Http 的类型是 Http(注意大写 H),Angular 会自动将它匹配到对应的服务实例。听起来很神奇?对于 JavaScript 开发者来说,这确实有点“黑魔法”的味道。
浏览器运行时,http 参数从哪来?
要知道,类型定义是 TypeScript 特有的特性,编译成 JavaScript 后按理说应该消失得无影无踪。那么浏览器中的 JavaScript 凭什么还能认出 http 参数该是什么?
秘密藏在 tsconfig.json 里的一个配置:emitDecoratorMetadata 设为 true。这个开关会把参数的类型信息作为元数据,嵌入到编译后的装饰器代码里。来看上面那段 TypeScript 编译后实际的样子(为了清晰,保留了 ES6 导入):
import { Component } from '@angular/core';
import { Http } from '@angular/http';
var ExampleComponent = (function() {
function ExampleComponent(http) {
this.http = http;
}
return ExampleComponent;
})();
ExampleComponent = __decorate(
[
Component({
selector: 'example-component',
template: 'I am a component
',
}),
__metadata('design:paramtypes', [Http]),
],
ExampleComponent
);
发现关键点了吗?__metadata('design:paramtypes', [Http]) 这一行把 Http 类型存储为元数据。因此 @Component 装饰器在运行时会被转换成普通的 ES5 函数,而 __decorate 负责把元数据打包在一起。Angular 拿到这个元数据后,就知道构造函数的第一参数应该注入 Http 令牌对应的实例,然后把它赋值给 this.http:
function ExampleComponent(http) {
this.http = http;
}
整个过程环环相扣:TypeScript 的类型信息通过 emitDecoratorMetadata 保留下来,装饰器元数据告诉 Angular 该注入什么,最终依赖注入系统优雅地完成了服务的装配。这就是 @Injectable 背后最核心的工作原理。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
HTML5视频播放器播放记录及断点续传实现
HTML5视频播放器断点续传需手动实现:通过timeupdate事件每5-10秒保存播放进度至localStorage,配合visibilitychange和beforeunload确保离开时存盘;页面加载后从本地读取进度,在loadedmetadata事件中设置currentTime恢复;注意处理视频时长变化、跨设备限制及移动端暂停问题。
全面详解JavaScript String类型处理多语言字符的实现方法
JavaScript的String类型底层采用UTF-16编码,处理中文、emoji等多语言字符时需注意代理对问题,不能直接用length或下标访问。推荐做法:用Array from或for of遍历真实字符,正则加u标志;截取用Array from() slice();大小写转换需指定locale参数;排序使用localeCompare实现本地化排序才
details标签在数据表格语义化中的正确应用
details标签语义上用于承载补充性说明,而非核心业务数据,不具备数据绑定、CRUD等操作能力,不能替代数据表格详细视图。在实际项目中应作为增强层使用,如折叠非必要信息,避免破坏主干结构。
手写递归遍历与标准查找的基准测试耗时对比
评估手写递归原型遍历与标准查找的时间开销,关键在于引擎的内联缓存机制。通过构造原型链、控制变量并用Benchmark js测试,结合DevTools分析可知,影响性能的核心是引擎能否将属性访问编译为内存偏移指令,而非递归层数本身。
Vue.js响应式系统:单向数据流与数据劫持协同机制
Vue响应式系统依靠单向数据流与数据劫持协同驱动视图更新。数据劫持拦截变量写入并触发依赖通知,事件系统负责采集用户操作,v-model仅为语法糖,本质是事件监听与手动赋值。单向流确保状态变更路径单一,提升可维护性。
- 日榜
- 周榜
- 月榜
相关攻略
2026-07-08 06:57
2026-07-08 06:56
2026-07-08 06:56
2026-07-08 06:56
2026-07-08 06:56
2026-07-08 06:56
2026-07-08 06:56
2026-07-08 06:55
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

