在 Angular 2 學習過程當中,相信不少初學者對 constructor 和 ngOnInit 的應用場景和區別會存在困惑,本文咱們會經過實際的例子,爲讀者一步步解開困惑。segmentfault
在 ES6 中就引入了類,constructor(構造函數) 是類中的特殊方法,主要用來作初始化操做,在進行類實例化操做時,會被自動調用。立刻來個例子:app
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 是 Angular 2 組件生命週期中的一個鉤子,Angular 2 中的全部鉤子和調用順序以下:this
ngOnChanges - 當數據綁定輸入屬性的值發生變化時調用code
ngOnInit - 在第一次 ngOnChanges 後調用component
ngDoCheck - 自定義的方法,用於檢測和處理值的改變對象
ngAfterContentInit - 在組件內容初始化以後調用繼承
ngAfterContentChecked - 組件每次檢查內容時調用生命週期
ngAfterViewInit - 組件相應的視圖初始化以後調用
ngAfterViewChecked - 組件每次檢查視圖時調用
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 方法內能獲取到輸入的屬性。
在 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 鉤子中去執行。如在組件獲取輸入屬性以後,需執行組件初始化操做等。
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 鉤子主要用於執行組件的其它初始化操做或獲取組件輸入的屬性值。