我是Angular的新手。当我在做Heros教程时,我注意到组件构造函数参数的类型必须是依赖项。换句话说,我必须将它包含在providers数组中。
例如:
import { SomeServiceClass } from '...';
@Component({
...
})
export class MyComponent implements OnInit {
constructor(input1: SomeServiceClass) { }
ngOnInit() {
}
}
除非我在providers数组中包含SomeServiceClass,否则此代码无效。我试过了input1: string
。它既不起作用!我相信它是完全有效的打字稿代码。问题必须是angular2实例化组件类的方式。
问题1 :如何将组件分类实际由Angular实例化?
而且,由于我从不实例化服务类,我无法想象将哪个服务类实例传递给组件构造函数。
问题2 :angular是否创建了一个服务实例供每个组件使用,或者为每个组件生成一个实例?
答案 0 :(得分:5)
除非我在providers数组中包含SomeServiceClass,否则此代码无效。我试过input1:string。它既不起作用也不行!我相信它是完全有效的打字稿代码。问题必须是angular2实例化组件类的方式。
您需要将SomeServiceClass
添加到某些providers
的{{1}}数组中的原因很简单。 Angular 选择不基于代码结构执行任何依赖性分析。他们可以在注入组件中使用ES模块导入来解决依赖关系并自动注册它。
作为证据,Aurelia就是这样做的。
换句话说,在Aurelia中,以下内容足以注入和使用依赖
ngModule
它有效。
如何将组件分类实际由Angular实例化?
而且,由于我从不实例化服务类,我无法想象将哪个服务类实例传递给组件构造函数。
JavaScript中的一个类实际上是一个构造函数,构造函数实际上是一个美化的工厂函数,而工厂函数确实是一个美化的函数。
这是什么意思?
这意味着Angular(和大多数DI框架)只需通过使用import {autoinject} from 'aurelia-framework';
import {SomeServiceClass} from '...';
@autoinject export class MyComponent {
constructor(input1: SomeServiceClass) {}
}
调用提供的类来首次请求服务时创建服务实例。
此类代码的简化版本可能类似于
new
angular是否创建了一个服务实例供每个组件使用,或者它为每个组件生成一个实例?
这个很棘手,默认情况下,每个应用程序只创建一个实例。
这是一个应用程序级单例,请求它的所有组件都接收相同的实例。
然而,Angular中也有不同的隐式和显式行为。
如果延迟加载的function instantiateComponent<T>(Component: new (...args: any[]) => T) {
const requiredDependencies = resolveDependencies(Component);
return new Component(...requiredDependencies);
}
function resolveDependencies(Dep: new (...args: any[]) => any): object[] {
const requiredDependencies = metaDataUtils.getDependencies(Dep);
return requiredDependencies.map(Dep => {
const alreadyCreatedDependency = injectorCache.find(dep => dep instanceof Dep);
if(alreadyCreatedDependency !== undefined) {
return alreadyCreatedDependency;
}
else {
const requiredDependencies = metaDataUtils.getDependencies(Dep);
// resolution is recursive
const newDependency = new Dep(...requiredDependencies.map(resolveDependencies));
injectorCache.push(newDependency);
return newDependency;
}
});
}
在其ngModule
数组中列出相同的服务,则将创建第二个实例,并且该实例将由延迟加载的模块的子项共享。这实际上是一种过度简化,但它已经令人困惑,并且鉴于模块是否被懒惰加载是由其消费者决定的,它可能导致严重和微妙的错误。
最后,组件可以在providers
元数据中明确声明自己的providers
。这样做的任何组件都将拥有该组件的所有实例创建和共享的新服务实例。
注意:只是在您说
时具体说明我注意到组件构造函数参数的类型必须是依赖项。
你不是严格正确的。依赖关系不是类型,它们是值。 TypeScript类型在编译时被完全擦除,实际注入的是值。类是值
@Component
但TypeScript也从其声明中推断出某些类型的存在。但是注入的是值class C {}
,而不是类型C
。