在 Angular 學(xué)習(xí)過程中,相信很多初學(xué)者對 constructor 和 ngOnInit 的應(yīng)用場景和區(qū)別會存在困惑,本文我們會通過實(shí)際的例子,為讀者一步步解開困惑。
在 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 是 Angular 組件生命周期中的一個鉤子,Angular 中的所有鉤子和調(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)能獲取到輸入的屬性。
在 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í)行初始化操作
}
}
在項(xiàng)目開發(fā)中我們要盡量保持構(gòu)造函數(shù)簡單明了,讓它只執(zhí)行簡單的數(shù)據(jù)初始化操作,因此我們會把其他的初始化操作放在 ngOnInit 鉤子中去執(zhí)行。如在組件獲取輸入屬性之后,需執(zhí)行組件初始化操作等。
因?yàn)楫?dāng) class 使用 extends 關(guān)鍵字實(shí)現(xiàn)繼承的時候,我們不能確保所繼承父類的有效性,那么就可能導(dǎo)致一些無法預(yù)知的行為。具體可以參考 - Angular 2 Forward Reference 這篇文章。
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í)例。
在 Angular 中 constructor 一般用于依賴注入或執(zhí)行簡單的數(shù)據(jù)初始化操作,ngOnInit 鉤子主要用于執(zhí)行組件的其它初始化操作或獲取組件輸入的屬性值。
更多建議: