Angular默认提供了生命周期钩子ngOnInit。

为什么要使用ngOnInit,如果我们已经有一个构造函数?


当前回答

构造函数是第一个执行的,当@input data为空时有时会发生这种情况! 所以我们使用构造函数注入服务,ngOnInit在后面发生。 构造函数示例:

 constructor(translate: TranslateService, private oauthService: OAuthService) {
    translate.setDefaultLang('En');
        translate.use('En');}

示例ngOnInit:

ngOnInit() {
    this.items = [
      { label: 'A', icon: 'fa fa-home', routerLink: ['/'] },
      { label: 'B', icon: 'fa fa-home', routerLink: ['/'] }]
}

我认为ngOnInit就像winForm中的InitialComponents()。

其他回答

构造函数: ES6类(这里是TypeScript)的构造函数方法是类本身的特性,而不是Angular的特性。当调用构造函数时,它不在Angular的控制范围内,这意味着它不是一个合适的钩子来告诉你Angular何时完成了组件的初始化。JavaScript引擎调用构造函数,而不是直接调用Angular。这就是为什么创建了ngOnInit(和AngularJS中的$onInit)生命周期钩子。记住这一点,有一个使用构造函数的合适场景。这就是我们想要利用依赖注入的时候——本质上是为了将依赖“连接”到组件中。

由于构造函数是由JavaScript引擎初始化的,TypeScript允许我们告诉Angular,我们需要将哪些依赖关系映射到特定的属性上。

ngOnInit只是给我们一个信号,表明Angular已经完成了组件的初始化。

这个阶段包括针对我们可能绑定到组件本身的属性的Change Detection的第一步——比如使用@Input()装饰器。

因此,@Input()属性在ngOnInit中是可用的,但是在构造函数中是未定义的

构造函数和ngOnInit之间的主要区别是ngOnInit是生命周期钩子,在构造函数之后运行。组件插值模板和输入初始值在构造函数中不可用,但在ngOnInit中可用。

实际的区别在于ngOnInit如何影响代码的结构。大多数初始化代码可以移动到ngOnInit -只要这不会产生竞争条件。

构造函数反模式

大量的初始化代码使得构造函数方法难以扩展、读取和测试。

将初始化逻辑与类构造函数分离的一个常用方法是将其移动到另一个方法,如init:

class Some {
  constructor() {
    this.init();
  }

  init() {...}
}

ngOnInit可以在组件和指令中实现这个目的:

constructor(
  public foo: Foo,
  /* verbose list of dependencies */
) {
  // time-sensitive initialization code
  this.bar = foo.getBar();
}

ngOnInit() {
  // rest of initialization code
}

依赖注入

类构造函数在Angular中的主要作用是依赖注入。在TypeScript中,构造函数也用于DI注释。几乎所有依赖项都作为属性分配给类实例。

普通的组件/指令构造函数已经足够大了,因为它可以由于依赖而有多行签名,在构造函数体中放置不必要的初始化逻辑会导致反模式。

异步的初始化

异步初始化构造函数通常可以被认为是反模式的,并且具有嗅觉,因为类实例化在异步例程之前完成,这可能会产生竞争条件。如果不是这样,ngOnInit和其他生命周期钩子是更好的地方,特别是因为它们可以从异步语法中受益:

constructor(
  public foo: Foo,
  public errorHandler: ErrorHandler
) {}

async ngOnInit() {
  try {
    await this.foo.getBar();
    await this.foo.getBazThatDependsOnBar();
  } catch (err) {
    this.errorHandler.handleError(err);
  }
}

如果存在竞争条件(包括组件在初始化错误时不应该出现),异步初始化例程应该在组件实例化之前发生,并被移动到父组件、路由器保护等。

单元测试

ngOnInit比构造函数更灵活,并为单元测试提供了一些好处,在这个回答中详细解释了这些好处。

考虑到ngOnInit不会在单元测试中的组件编译时自动调用,在ngOnInit中调用的方法可以在组件实例化后被监视或模拟。

在特殊情况下,ngOnInit可以完全stub,为其他组件单元(例如,一些模板逻辑)提供隔离。

继承

子类只能扩充构造函数,不能替换它们。

由于不能在super()之前引用this,这限制了初始化优先级。

考虑到Angular组件或指令使用ngOnInit进行时间不敏感的初始化逻辑,子类可以选择是否调用super.ngOnInit(),以及以下情况:

ngOnInit() {
  this.someMethod();
  super.ngOnInit();
}

仅使用构造函数是不可能实现的。

简短而简单的回答是,

构造函数:构造函数是在构造组件时(默认情况下)运行的默认方法。当创建类的实例时,也会调用构造函数(默认方法)。换句话说,当构建组件或/和创建实例时,调用构造函数(默认方法)并调用其中编写的相关代码。基本上,在Angular2中,当组件被构造以供进一步使用时,它被用来注入服务之类的东西。

OnInit: ngOnInit是组件的生命周期钩子,当组件初始化时,它首先在构造函数(默认方法)之后运行。

因此,你的构造函数将首先被调用,Oninit将在构造函数方法之后被调用。

boot.ts

import {Cmomponent, OnInit} from 'angular2/core';
import {ExternalService} from '../externalService';

export class app implements OnInit{
   constructor(myService:ExternalService)
   {
           this.myService=myService;
   }

   ngOnInit(){
     // this.myService.someMethod() 
   }
}

资源:生命周期钩子

你可以查看这个小演示,它展示了这两件事的实现。

两种方法都有不同的目标/职责。构造函数(这是语言支持的特性)的任务是确保表示不变量成立。否则,通过给成员正确的值来确保实例是有效的。“正确”的含义由开发者决定。

onInit()方法(这是一个angular概念)的任务是允许在正确的对象上调用方法(表示不变)。每个方法都应该依次确保在方法终止时表示不变量保持不变。

构造函数应该用来创建“正确的”对象,onInit方法让你有机会在一个定义良好的实例中调用方法调用。

Constructor()用于进行依赖注入。

ngOnInit(), ngOnChanges()和ngOnDestroy()等都是生命周期方法。ngOnChanges()将是第一个被调用的,在ngOnInit()之前,当绑定属性的值发生变化时,如果没有变化,它将不会被调用。ngOnDestroy()在移除组件时被调用。要使用它,OnDestroy需要由类实现。