在 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 中的所有鉤子和呼叫順序如下:
-
ngOnChanges – 當資料繫結輸入屬性的值發生變化時呼叫
-
ngOnInit – 在第一次 ngOnChanges 後呼叫
-
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 方法內能獲取到輸入的屬性。
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 鉤子主要用於執行元件的其它初始化操作或獲取元件輸入的屬性值。