构造函数和ngOnInit的区别
Angular默认提供生命周期钩子ngOnInit
。 任何人都可以告诉我有关ngOnInit
的用法,如果我们已经有一个constructor
?
Constructor
是类实例化时执行的类的默认方法,并确保在类及其子类中的字段的正确初始化。 Angular或更好的DI分析构造函数参数,当它通过调用new MyClass()
创build新实例时,它会尝试查找与构造函数参数types相匹配的提供者,parsing它们并将它们传递给构造函数
new MyClass(someArg);
ngOnInit
是ngOnInit
的一个生命周期钩子,表示Angular创build了组件。
我们必须导入OnInit
以便像这样使用(实际上实现OnInit
不是强制性的,但被认为是很好的做法):
import {Component, OnInit} from '@angular/core';
那么要使用OnInit
的方法,我们必须像这样在类中实现。
export class App implements OnInit{ constructor(){ //called first time before the ngOnInit() } ngOnInit(){ //called after the constructor and called after the first ngOnChanges() } }
在你的指令的数据绑定属性被初始化之后,实现这个接口来执行自定义的初始化逻辑。 ngOnInit在第一次检查伪指令的数据绑定属性之后,以及在其任何子项被检查之前调用。 当指令被实例化时,它只被调用一次。
大多数情况下,我们使用ngOnInit
进行所有初始化/声明,并避免在构造函数中工作。 构造函数只能用于初始化类成员,不应该做实际的“工作”。
所以你应该使用constructor()
来设置dependency injection,而不是其他的。 ngOnInit()是“开始”的好地方 – 它是parsing组件绑定的地方。
有关更多信息,请参阅:
-
Angular 2组件构造函数与OnInit
我认为最好的例子是使用服务。 假设我想在组件获取“激活”时从服务器获取数据。 假设我在从服务器获取数据后还想对数据做一些额外的事情,也许我得到一个错误,并希望以不同的方式logging它。
使用ngOnInit通过构造函数很容易,它也限制了我需要添加到我的应用程序的多less个callback层。
例如:
export class Users implements OnInit{ user_list: Array<any>; constructor(private _userService: UserService){ }; ngOnInit(){ this.getUsers(); }; getUsers(){ this._userService.getUsersFromService().subscribe(users => this.user_list = users); }; }
用我的构造函数,我可以调用我的_userService并填充我的user_list,但也许我想用它做一些额外的事情。 像确保一切都是upper_case,我不完全确定我的数据是如何通过。
所以它使得使用ngOnInit变得更容易。
export class Users implements OnInit{ user_list: Array<any>; constructor(private _userService: UserService){ }; ngOnInit(){ this.getUsers(); }; getUsers(){ this._userService.getUsersFromService().subscribe(users => this.user_list = users); this.user_list.toUpperCase(); }; }
这使得它更容易看到,所以我只是在我的组件中调用我的函数,而不是在其他地方挖掘它。 真的,这只是另一个工具,你可以使它更容易阅读和使用在未来。 另外我发现把一个函数调用放在一个构造函数中是一个非常糟糕的做法!
第一个(构造函数)与类实例相关,与Angular2无关。 我的意思是可以在任何类上使用构造函数。 你可以在这里为新创build的实例进行一些初始化处理。
第二个对应于Angular2组件的生命周期钩子:
引自官方的网站:
- input或输出绑定值更改时调用
ngOnChanges
ngOnInit
在第一个ngOnChanges
之后被调用
所以你应该使用ngOnInit
如果初始化处理依赖于组件的绑定(例如用@Input
定义的组件参数),否则构造函数就足够了…
文章Angular中的Constructor和ngOnInit的本质区别从多个angular度探讨了不同之处。 这个答案提供了与组件初始化过程有关的最重要的不同解释,也说明了不同的使用情况。
angular引导程序由两个主要阶段组成:
- 构build组件树
- 运行变化检测
当Angular构造组件树时,组件的构造函数被调用。 所有生命周期挂钩都作为运行更改检测的一部分进行调用。
当Angular构造组件树时,根模块注入器已经被configuration,所以你可以注入任何全局依赖。 另外,当Angular实例化一个子组件类时,父组件的注入器也已经被设置好了,所以你可以注入在父组件上定义的提供者,包括父组件本身。 组件构造函数是在注入器上下文中调用的唯一方法,所以如果您需要依赖关系,那么这是唯一获取这些依赖关系的地方。
当Angular开始更改检测时,将构造组件树并调用树中所有组件的构造函数。 而且每个组件的模板节点都被添加到DOM中。 @Input
通信机制是在更改检测期间处理的,因此您不能期望在构造函数中具有可用的属性。 它将在ngOnInit
之后ngOnInit
。
我们来看一个简单的例子。 假设您有以下模板:
<my-app> <child-comp [i]='prop'>
所以Angular开始引导应用程序。 正如我所说,它首先为每个组件创build类。 所以它调用MyAppComponent
构造函数。 它还创build了一个DOM节点,它是my-app
组件的主机元素。 然后继续为child-comp
创build一个主机元素并调用ChildComponent
构造函数。 在这个阶段,它并不真正关心i
input绑定和任何生命周期钩子。 所以当这个过程完成后,Angular以下面的组件视图树结束:
MyAppView - MyApp component instance - my-app host element data ChildCompnentView - ChildComponent component instance - child-comp host element data
然后才运行更改检测并更新my-app
绑定,并调用MyAppComponent类的ngOnInit。 然后继续更新child-comp
的绑定,并调用ChildComponent类的ngOnInit。
您可以在构造函数或ngOnInit
执行初始化逻辑,具体取决于您需要的。 例如,文章以下是如何在评估@ViewChild查询之前获取ViewContainerRef,以显示在构造函数中可能需要执行的初始化逻辑types。
以下是一些可以帮助你更好地理解这个主题的文章:
- 您需要了解有关Angular中更改检测的所有信息
- Angular的$摘要在Angular的新版本中重生
- 在Angular中更新属性绑定的机制
简单而简单的答案是,
Constructor
: constructor
是构造组件时的default method
( 由deafult )运行。 当你创build一个类an instance
时,也会调用constructor(default method)
。 换句话说,当组件正在constructed or/and an instance is created constructor(default method)
被调用并调用相关代码。 基本上和一般在Angular2
,当组件被构造以供进一步使用时,它用于注入诸如services
东西。
OnInit
:ngOnInit是组件的初始化后,在constructor(default method)
之后运行的组件的生命周期钩子。
所以,你的构造函数将被首先调用,Oninit将在构造函数方法之后被调用。
boot.ts
import {Cmomponent, OnInit} from 'angular2/core'; import {ExternalService} from '../externalService'; export class app implements OnInit{ constructor(myService:ExternalService) { this.myService=myService; } ngOnInit(){ // this.myService.someMethod() } }
资源: LifeCycle钩子
你可以查看这个小演示 ,它显示了这两个东西的实现。
OK,首先ngOnInit
是Angular生命周期的一部分,而constructor
是ES6类的一部分,所以主要区别从这里开始…
看下面我创build的图表,显示Angular的生命周期。
在Angular2和更高版本中,我们使用constructor
为我们执行DI(Dependency Injection)
,而在Angular1中,通过调用String方法并检查注入哪个依赖项来实现。
正如你在上面的图中看到的, ngOnInit
在构造函数准备好之后发生, ngOnChnages
在组件准备好之后被触发。 所有的初始化都可以在这个阶段发生,一个简单的例子就是注入一个服务并在初始化时初始化它。
好的,我也分享一个示例代码供你看,看看我们如何在下面的代码中使用ngOnInit
和constructor
:
import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; @Component({ selector: 'my-app', template: `<h1>App is running!</h1> <my-app-main [data]=data></<my-app-main>`, styles: ['h1 { font-weight: normal; }'] }) class ExampleComponent implements OnInit { constructor(private router: Router) {} //Dependency injection in the constructor // ngOnInit, get called after Component initialised! ngOnInit() { console.log('Component initialised!'); } }
为了testing这个,我写了这个代码,从NativeScript教程中借用:
user.ts
export class User { email: string; password: string; lastLogin: Date; constructor(msg:string) { this.email = ""; this.password = ""; this.lastLogin = new Date(); console.log("*** User class constructor " + msg + " ***"); } Login() { } }
login.component.ts
import {Component} from "@angular/core"; import {User} from "./../../shared/user/user" @Component({ selector: "login-component", templateUrl: "pages/login/login.html", styleUrls: ["pages/login/login-common.css", "pages/login/login.css"] }) export class LoginComponent { user: User = new User("property"); // ONE isLoggingIn:boolean; constructor() { this.user = new User("constructor"); // TWO console.log("*** Login Component Constructor ***"); } ngOnInit() { this.user = new User("ngOnInit"); // THREE this.user.Login(); this.isLoggingIn = true; console.log("*** Login Component ngOnInit ***"); } submit() { alert("You're using: " + this.user.email + " " + this.user.lastLogin); } toggleDisplay() { this.isLoggingIn = !this.isLoggingIn; } }
控制台输出
JS: *** User class constructor property *** JS: *** User class constructor constructor *** JS: *** Login Component Constructor *** JS: *** User class constructor ngOnInit *** JS: *** Login Component ngOnInit ***
上面的答案并没有真正回答原始问题的这个方面:什么是生命周期钩子? 我花了一段时间才明白这是什么意思,直到我这样想。
1)说你的组件是一个人。 人类的生命包含了许多阶段的生活,然后我们到期了。
2)我们的人的组成部分可以有以下的生命周期脚本:出生,婴儿,小学,青年,中年,成年,死亡,处置。
3)说你想有一个function来创build孩子。 为了避免这个问题变得复杂而幽默,你只希望你的function在人类生活的青年阶段被调用。 因此,您需要开发一个只在父组件处于Young Adult阶段时才有效的组件。 钩子通过发信号通知生命的这个阶段,并让你的组件采取行动来帮助你做到这一点。
好玩的东西。 如果你让你的想象力去实际编码这样的事情变得复杂和有趣。
像许多其他语言一样,您可以在类级别,构造函数或方法中初始化variables。 开发者决定什么是最好的在他们的具体情况。 但是,下面是决定时的最佳实践清单。
类级variables
通常,你将在这里声明你所有的variables,这些variables将在你的其他组件中使用。 你可以初始化它们,如果这个值不依赖于别的东西,或者使用const关键字来创build常量,如果它们不会改变的话。
export class TestClass{ let varA: string = "hello"; }
构造函数
通常最好的做法是不要在构造函数中做任何事情,只是将它用于将被注入的类。 大多数时候你的构造函数应该是这样的:
constructor(private http: Http, private customService: CustomService) {}
这将自动创build类级别的variables,所以你将有权访问customService.myMethod()
而不必手动。
NgOnInit
NgOnit是Angular 2框架提供的生命周期钩子。 您的组件必须实现OnInit
才能使用它。 在构造函数被调用并且所有variables被初始化之后,这个生命周期钩子被调用。 初始化的大部分应该在这里。 您将确信Angular已经正确初始化了您的组件,并且您可以开始在OnInit
执行您需要的任何逻辑,而在您的组件尚未正确加载完成时执行任何操作。
这是一张详细说明被调用顺序的图片:
https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html
TLDR
如果您正在使用Angular 2框架并需要与某些生命周期事件交互,请使用框架提供的方法来避免问题。
构造函数是JavaScript中的一个方法,被认为是es6中类的一个特性。当类被实例化时,它立即运行构造函数,无论它是否在Angular框架中使用。所以它被JavaScript引擎调用,Angular没有控制。
import {Component} from '@angular/core'; @Component({}) class CONSTRUCTORTEST { //This is called by Javascript not the Angular. constructor(){ console.log("view constructor initialised"); } }
“ConstructorTest”类在下面实例化,所以它在内部调用构造函数(所有这些都是通过JavaScript(es6)no Angular)来实现的。
new CONSTRUCTORTEST();
这就是Angular.ngOnInit在Angular初始化组件时呈现ngOnInit生命周期钩子的原因。
import {Component} from '@angular/core'; @Component({}) class NGONINITTEST implements onInit{ constructor(){} //ngOnInit calls by Angular ngOnInit(){ console.log("Testing ngOnInit"); } }
首先我们将实例化类,如下所示,即时运行的构造方法。
let instance = new NGONINITTEST();
如果需要,ngOnInit被Angular调用,如下所示:
instance.ngOnInit();
但是你可能会问为什么我们在Angular中使用构造函数?
答案就是dependency injection 。正如前面提到的,当类实例化(在Angular调用ngOnInit之前),JavaScript引擎立即调用构造函数,所以typescript帮助我们获得构造函数中定义的依赖types,并最终告诉Angular在特定组件中使用哪种types的依赖关系。
这里要注意两点:
- 每当创build该类的对象时,都会调用构造函数。
- 一旦组件被创build,ngOnInit就会被调用。
两者有不同的可用性。
两种方法都有不同的目标/责任。 构造函数(这是一种语言支持的function)的任务是确保表示不变保持不变。 否则,通过给成员赋予正确的值来确保实例是有效的。 开发者决定什么是“正确”的意思。
onInit()方法(这是一个angular度概念)的任务是允许在正确的对象(表示不变)上调用方法。 当方法终止时,每个方法都应该确保表示不变式成立。
应该使用构造函数来创build“正确的”对象,onInit方法使您有机会在定义好的实例中调用方法调用。
constructor()
被用来做dependency injection。
ngOnInit()
, ngOnChanges()
和ngOnDestroy()
等是生命周期方法。 ngOnChanges()
将在ngOnInit()
之前被第一个调用,当绑定属性的值发生变化时,如果没有变化,它将不会被调用。 ngOnDestroy()
在组件被移除时被调用。 要使用它, OnDestroy
需要由类实现。
在angular度生命周期
1)angular度注入器检测构造函数参数('s)并实例化类。
2)下一个angular度调用生命周期
有angular度的生命周期钩子
ngOnChanges – >调用指令参数绑定。
ngOnInit – >开始angular度渲染…
用angular度生命周期的状态调用其他方法。
- 如何观看和编译所有的TypeScript源代码?
- 在接口定义中可以使用getters / setter吗?
- Angular 2 beta.17:Property'map'在types'Observable <Response>'上不存在
- Typescript:接口与types
- Angular2 – 应该在模板中访问私有variables?
- Typescript:如何为方法参数中使用的函数callback(如任何函数types,不是通用的)定义types
- Typescript是否支持? 运营商? (那叫什么?)
- 什么是打字稿?
- 如何用Jasmine为私有方法编写Angular 2 / TypeScript的unit testing