Angular中的元件(component)啟動的時候,分別會觸發兩個事件:

  • constructor
  • ngOnInit
    constructor是javascript中class產生出來時候會執行的建構式
    ngOnInit則是Angular眾多生命週期中的其中之一,會在元件(component)啟動的時候觸發,

針對這兩個來做個簡單的實驗與比較。

比較一:元件啟動的時候,ngOnInit和constructor啟動順序

分別對ngOnInit和constructor下console觀察兩者顯示的先後順序

import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.css']
})
export class TestComponent implements OnInit {
  constructor() {
    console.log('constructor啟動了')
   }
  ngOnInit() {
    console.log('ngOnInit啟動了')
  }
}

看一下測試結果:

小結一

呼叫順序為constructor先再ngOnInit

比較二:分別在constructor和ngOnInit賦予變數值

先定義三個變數,分別都給予初始值文字”noValue”

normalValue='noValue'
constructorValue="noValue"
ngOnInitValue="noValue"

將三個變數顯示在頁面上面

normalValue的值:{{normalValue}}

constructor的值:{{constructorValue}}

ngOnInit的值:{{ngOnInitValue}}

接下來,分別在不同階段賦予這三個變數其他文字,如果是從constructor賦值,顯示文字:「從constructor取值」;同樣地,如果從ngOnInit賦值,顯示文字:「從ngOnInit取值」

export class TestComponent implements OnInit {
  normalValue='noValue'
  constructorValue="noValue"
  ngOnInitValue="noValue"
  constructor() {
    console.log('constructor啟動了')
    this.constructorValue='從constructor取值'
    this.normalValue='從constructor取值'
   }
  ngOnInit() {
    console.log('ngOnInit啟動了')
    this.ngOnInitValue='從ngOnInit取值'
    this.normalValue='從ngOnInit取值'
  }
}

看一下結果:

小結二

不論在constructor或在ngOnInit賦值都是沒有問題的。
如果在constructor和ngOnInit連續賦值的話,就會依照小結一的結論照順序賦值,最後得到ngOnInit給予的值。

比較三:從外部輸入值到元件當中

元件的值可以使用@Input方法,從外部輸入數值。
例如,從外部輸入變數name的值為「Angular」,分別在constructor和ngOnInit下console觀察變數name的狀態

export class ChildComponent implements OnInit,OnChanges {
  @Input() name
  child
  constructor() {
    console.log(this.name)
   }

  ngOnInit() {
    console.log(this.name)
  }
}

看一下結果:

constructor取不到變數內容,是undefined;而ngOnInit正確取到輸入的內容。

從這個比較可以推論出,因為元件的內容輸入的時機涉及Angular元件的設計,所以將納入Angular的生命週期裡面,但是constructor僅是class中的方法,不在Angular的掌控範圍之內,無法得到Angular生命週期的內容。

小結三

如果從外部輸入內容,因為牽涉到Angular的生命週期,內容必須在ngOnInit裡面取得,無法在constructor取得

比較四:從注入的服務取得服務資料

元件的值也可以從服務(service)取得,於是建立一個服務,並且建立一個方法,會返回一串文字「get something from service」
在此建立兩個變數「serviceContentA」和「serviceContentB」,分別在constructor和ngOnInit呼叫服務並且賦值,觀察是否能正確取得值

export class ChildComponent implements OnInit,OnChanges {
  serviceContentA
  serviceContentB
  constructor(
    private appService:AppService
  ) {
    this.serviceContentA=appService.getSomethingFromService()
    console.log('serviceContentInConstructor:',this.serviceContentA)
   }

  ngOnInit() {
    this.serviceContentB=this.appService.getSomethingFromService()
    console.log('serviceContentInngOnInit:',this.serviceContentB)
  }
}

看一下結果

小結四

服務不論在constructor或ngOnInit賦值,都可以正確取得值

結論:

  • 觸發順序為construcor再ngOnInit
  • 元件內部都操作,例如:在元件內部賦值或是從服務取值,不論在constructor或ngOnInit是沒有差別的
  • 元件外部輸入內部的操作,例如:使用@Input方法,只有ngOnInit可以正確取到值

因此ngOnInit和constructor雖然都會在啟動時觸發,推薦各自最安全也最不會出問題的使用時機。

  • ngOnInit:處理預設值與初始動作
  • constructor:處理注入各種元件的工作,避免處理注入以外的工作。因為不在Angular生命週期裡面,Angular掌握不到。

本次實驗的範例程式碼