Angular 2 constructor & ngOnInit

semlinker發表於2019-02-16

在 Angular 2 學習過程中,相信很多初學者對 constructor 和 ngOnInit 的應用場景和區別會存在困惑,本文我們會通過實際的例子,為讀者一步步解開困惑。

constructor

在 ES6 中就引入了類,constructor(建構函式) 是類中的特殊方法,主要用來做初始化操作,在進行類例項化操作時,會被自動呼叫。馬上來個例子:

class AppComponent {
  constructor(name) {
    console.log(`Constructor initialization`);
    this.name = name;
  }
}

let appCmp = new AppComponent(`AppCmp`);
console.log(appCmp.name); 

以上程式碼執行後,控制檯的輸出結果:

Constructor initialization
AppCmp

接下來我們看一下轉換後的 ES5 程式碼:

var AppComponent = (function () {
    function AppComponent(name) {
        console.log(`Constructor initialization`);
        this.name = name;
    }
    return AppComponent;
}());

var appCmp = new AppComponent(`AppCmp`);
console.log(appCmp.name);

ngOnInit

ngOnInit 是 Angular 2 元件生命週期中的一個鉤子,Angular 2 中的所有鉤子和呼叫順序如下:

  1. ngOnChanges – 當資料繫結輸入屬性的值發生變化時呼叫

  2. ngOnInit – 在第一次 ngOnChanges 後呼叫

  3. ngDoCheck – 自定義的方法,用於檢測和處理值的改變

  4. ngAfterContentInit – 在元件內容初始化之後呼叫

  5. ngAfterContentChecked – 元件每次檢查內容時呼叫

  6. ngAfterViewInit – 元件相應的檢視初始化之後呼叫

  7. ngAfterViewChecked – 元件每次檢查檢視時呼叫

  8. ngOnDestroy – 指令銷燬前呼叫

其中 ngOnInit 用於在 Angular 獲取輸入屬性後初始化元件,該鉤子方法會在第一次 ngOnChanges 之後被呼叫。

另外需要注意的是 ngOnInit 鉤子只會被呼叫一次,我們來看一下具體示例:

import { Component, OnInit } from `@angular/core`;

@Component({
  selector: `my-app`,
  template: `
    <h1>Welcome to Angular World</h1>
    <p>Hello {{name}}</p>
  `,
})
export class AppComponent implements OnInit {

  name: string = ``;

  constructor() {
    console.log(`Constructor initialization`);
    this.name = `Semlinker`;
  }

  ngOnInit() {
    console.log(`ngOnInit hook has been called`);
  }
}

以上程式碼執行後,控制檯的輸出結果:

Constructor initialization
ngOnInit hook has been called

接下來我們再來看一個 父 – 子元件傳參的例子:

parent.component.ts

import { Component } from `@angular/core`;

@Component({
  selector: `exe-parent`,
  template: `
    <h1>Welcome to Angular World</h1>
    <p>Hello {{name}}</p>
    <exe-child [pname]="name"></exe-child>
  `,
})
export class ParentComponent {
  name: string = ``;

  constructor() {
    this.name = `Semlinker`;
  }
}

child.component.ts

import { Component, Input, OnInit } from `@angular/core`;

@Component({
    selector: `exe-child`,
    template: `
     <p>父元件的名稱:{{pname}} </p>
    `
})
export class ChildComponent implements OnInit {
    @Input()
    pname: string; // 父元件的名稱

    constructor() {
        console.log(`ChildComponent constructor`, this.pname); // Output:undefined
    }

    ngOnInit() {
        console.log(`ChildComponent ngOnInit`, this.pname);
    }
}

以上程式碼執行後,控制檯的輸出結果:

ChildComponent constructor undefined
ChildComponent ngOnInit Semlinker

我們發現在 ChildComponent 建構函式中,是無法獲取輸入屬性的值,而在 ngOnInit 方法中,我們能正常獲取輸入屬性的值。因為 ChildComponent 元件的建構函式會優先執行,當 ChildComponent 元件輸入屬性變化時會自動觸發 ngOnChanges 鉤子,然後在呼叫 ngOnInit 鉤子方法,所以在 ngOnInit 方法內能獲取到輸入的屬性。

constructor 應用場景

在 Angular 2 中,建構函式一般用於依賴注入或執行一些簡單的初始化操作。

import { Component, ElementRef } from `@angular/core`;

@Component({
  selector: `my-app`,
  template: `
    <h1>Welcome to Angular World</h1>
    <p>Hello {{name}}</p>
  `,
})
export class AppComponent {
  name: string = ``;

  constructor(public elementRef: ElementRef) { // 使用構造注入的方式注入依賴物件
    this.name = `Semlinker`; // 執行初始化操作
  }
}

ngOnInit 應用場景

在專案開發中我們要儘量保持建構函式簡單明瞭,讓它只執行簡單的資料初始化操作,因此我們會把其他的初始化操作放在 ngOnInit 鉤子中去執行。如在元件獲取輸入屬性之後,需執行元件初始化操作等。

我有話說

1.在ES6 或 TypeScript 中的 Class 是不會自動提升的

因為當 class 使用 extends 關鍵字實現繼承的時候,我們不能確保所繼承父類的有效性,那麼就可能導致一些無法預知的行為。具體可以參考 – Angular 2 Forward Reference 這篇文章。

2.TypeScrip 中 Class 靜態屬性和成員屬性的區別

AppComponent.ts

class AppComponent {
  static type: string = `component`;
  name: string;

  constructor() {
    this.name = `AppComponent`;
  }
}

轉化後的 ES5 程式碼:

var AppComponent = (function () {
    function AppComponent() {
        this.name = `AppComponent`;
    }
    return AppComponent;
}());
AppComponent.type = `component`;

通過轉換後的程式碼,我們可以知道類中的靜態屬性是屬於 AppComponent 建構函式的,而成員屬性是屬於 AppComponent 例項。

總結

在 Angular 2 中 constructor 一般用於依賴注入或執行簡單的資料初始化操作,ngOnInit 鉤子主要用於執行元件的其它初始化操作或獲取元件輸入的屬性值。

相關文章