constructor 與 ngOnInit

2018-08-28 10:28 更新

查看新版Angular constructor vs ngOnInit

在 Angular 學(xué)習(xí)過程中,相信很多初學(xué)者對 constructor 和 ngOnInit 的應(yīng)用場景和區(qū)別會存在困惑,本文我們會通過實(shí)際的例子,為讀者一步步解開困惑。

constructor

在 ES6 中就引入了類,constructor(構(gòu)造函數(shù)) 是類中的特殊方法,主要用來做初始化操作,在進(jìn)行類實(shí)例化操作時,會被自動調(diào)用。馬上來個例子:

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


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

以上代碼運(yùn)行后,控制臺的輸出結(jié)果:

Constructor initialization
AppCmp

接下來我們看一下轉(zhuǎn)換后的 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 組件生命周期中的一個鉤子,Angular 中的所有鉤子和調(diào)用順序如下:

  1. ngOnChanges - 當(dāng)數(shù)據(jù)綁定輸入屬性的值發(fā)生變化時調(diào)用
  2. ngOnInit - 在第一次 ngOnChanges 后調(diào)用
  3. ngDoCheck - 自定義的方法,用于檢測和處理值的改變
  4. ngAfterContentInit - 在組件內(nèi)容初始化之后調(diào)用
  5. ngAfterContentChecked - 組件每次檢查內(nèi)容時調(diào)用
  6. ngAfterViewInit - 組件相應(yīng)的視圖初始化之后調(diào)用
  7. ngAfterViewChecked - 組件每次檢查視圖時調(diào)用
  8. ngOnDestroy - 指令銷毀前調(diào)用

其中 ngOnInit 用于在 Angular 獲取輸入屬性后初始化組件,該鉤子方法會在第一次 ngOnChanges 之后被調(diào)用。

另外需要注意的是 ngOnInit 鉤子只會被調(diào)用一次,我們來看一下具體示例:

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');
  }
}

以上代碼運(yùn)行后,控制臺的輸出結(jié)果:

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);
    }
}

以上代碼運(yùn)行后,控制臺的輸出結(jié)果:

ChildComponent constructor undefined
ChildComponent ngOnInit Semlinker

我們發(fā)現(xiàn)在 ChildComponent 構(gòu)造函數(shù)中,是無法獲取輸入屬性的值,而在 ngOnInit 方法中,我們能正常獲取輸入屬性的值。因?yàn)?ChildComponent 組件的構(gòu)造函數(shù)會優(yōu)先執(zhí)行,當(dāng) ChildComponent 組件輸入屬性變化時會自動觸發(fā) ngOnChanges 鉤子,然后在調(diào)用 ngOnInit 鉤子方法,所以在 ngOnInit 方法內(nèi)能獲取到輸入的屬性。

constructor 應(yīng)用場景

在 Angular 中,構(gòu)造函數(shù)一般用于依賴注入或執(zhí)行一些簡單的初始化操作。

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) { // 使用構(gòu)造注入的方式注入依賴對象
    this.name = 'Semlinker'; // 執(zhí)行初始化操作
  }
}

ngOnInit 應(yīng)用場景

在項(xiàng)目開發(fā)中我們要盡量保持構(gòu)造函數(shù)簡單明了,讓它只執(zhí)行簡單的數(shù)據(jù)初始化操作,因此我們會把其他的初始化操作放在 ngOnInit 鉤子中去執(zhí)行。如在組件獲取輸入屬性之后,需執(zhí)行組件初始化操作等。

我有話說

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

因?yàn)楫?dāng) class 使用 extends 關(guān)鍵字實(shí)現(xiàn)繼承的時候,我們不能確保所繼承父類的有效性,那么就可能導(dǎo)致一些無法預(yù)知的行為。具體可以參考 - Angular 2 Forward Reference 這篇文章。

TypeScrip 中 Class 靜態(tài)屬性和成員屬性的區(qū)別

AppComponent.ts

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


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

轉(zhuǎn)化后的 ES5 代碼:

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

通過轉(zhuǎn)換后的代碼,我們可以知道類中的靜態(tài)屬性是屬于 AppComponent 構(gòu)造函數(shù)的,而成員屬性是屬于 AppComponent 實(shí)例。

總結(jié)

在 Angular 中 constructor 一般用于依賴注入或執(zhí)行簡單的數(shù)據(jù)初始化操作,ngOnInit 鉤子主要用于執(zhí)行組件的其它初始化操作或獲取組件輸入的屬性值。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號