构造函数和ngOnInit之间的区别

时间:2016-03-03 05:14:04

标签: angular typescript ngoninit

Angular默认提供生命周期钩子ngOnInit

如果我们已经拥有ngOnInit

,为什么要使用constructor

29 个答案:

答案 0 :(得分:871)

Constructor是在实例化类时执行的类的默认方法,并确保在类及其子类中正确初始化字段。 Angular或更好的Dependency Injector(DI)分析构造函数参数,当它通过调用new MyClass()创建新实例时,它会尝试查找与构造函数参数类型匹配的提供程序,解析它们并将它们传递给构造函数,如< / p>

new MyClass(someArg);

ngOnInit是Angular2调用的生命周期钩子,表示Angular已完成创建组件。

我们必须导入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进行所有初始化/声明,并避免在构造函数中使用的东西。构造函数应仅用于初始化类成员,但不应该实际执行&#34; work&#34;。

因此,您应该使用constructor()来设置依赖注入,而不是其他。 ngOnInit()是开始&#34;更好的地方。 - 组件&#39;绑定得到解决。

有关更多信息,请参阅此处:

答案 1 :(得分:101)

文章The essential difference between Constructor and ngOnInit in Angular从多个角度探讨了差异。这个答案提供了与组件初始化过程相关的最重要的差异解释,它也显示了不同的用法。

Angular bootstrap过程包括两个主要阶段:

  • 构建组件树
  • 运行变更检测

当Angular构造组件树时,将调用组件的构造函数。所有生命周期挂钩都被称为运行更改检测的一部分。

当Angular构造组件树时,已经配置了根模块注入器,因此您可以注入任何全局依赖项。此外,当Angular实例化子组件类时,父组件的注入器也已设置,因此您可以注入在父组件上定义的提供程序,包括父组件本身。组件构造函数是在注入器上下文中调用的唯一方法,因此如果您需要任何依赖项,那么这是获取这些依赖项的唯一位置。

当Angular开始更改检测时,构造组件树并调用树中所有组件的构造函数。此外,每个组件的模板节点都会添加到DOM中。在更改检测期间处理@Input通信机制,因此您不能期望在构造函数中具有可用的属性。它将在ngOnInit之后提供。

让我们看一个简单的例子。假设您有以下模板:

<my-app>
   <child-comp [i]='prop'>

所以Angular开始引导应用程序。正如我所说,它首先为每个组件创建类。所以它调用MyAppComponent构造函数。它还创建了一个DOM节点,它是my-app组件的主机元素。然后继续为child-comp创建主机元素并调用ChildComponent构造函数。在这个阶段,它并不真正关心i输入绑定和任何生命周期钩子。因此,当此过程完成时,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中执行初始化逻辑,具体取决于您需要的内容。例如,文章Here is how to get ViewContainerRef before @ViewChild query is evaluated显示了在构造函数中可能需要执行的初始化逻辑类型。

以下是一些可以帮助您更好地理解该主题的文章:

答案 2 :(得分:85)

我认为最好的例子就是使用服务。让我们说当我的组件被激活时,我想从我的服务器中获取数据&#39;。让我们说,在我从服务器上获取数据后,我还想对数据做一些额外的事情,也许我收到错误并希望以不同的方式记录它。

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


}

使用我的构造函数我可以调用我的_userService并填充我的user_list,但也许我想用它做一些额外的事情。就像确保一切都是大写的一样,我不完全确定我的数据是如何通过的。

因此,使用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();
    };


}

它使得查看更容易,因此我在初始化时只需在我的组件中调用我的函数,而不是在其他地方挖掘它。它实际上只是您可以使用的另一种工具,以便将来更容易阅读和使用。另外我发现将函数调用放在构造函数中真的很糟糕!

答案 3 :(得分:60)

好的,首先ngOnInit Angular生命周期的一部分,而constructor ES6 的一部分JavaScript类,所以主要区别从这里开始!...

请看下面我创建的图表,其中显示了Angular的生命周期。

ngOnInit vs constructor

在Angular2 +中,我们使用constructor为我们执行DI(Dependency Injection),而在Angular 1中,它通过调用String方法并检查注入了哪个依赖项来实现。

正如您在上图中看到的那样,ngOnInit在构造函数准备好后发生ngOnChnages并在组件为我们准备好后被触发。所有初始化都可以在此阶段进行,一个简单的示例是注入服务并在init上初始化它。

好的,我也分享了一个示例代码供您查看,看看我们如何在下面的代码中使用ngOnInitconstructor

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

答案 4 :(得分:46)

第一个(构造函数)与类实例化有关,与Angular2无关。我的意思是构造函数可以在任何类上使用。您可以为新创建的实例添加一些初始化处理。

第二个对应于Angular2组件的生命周期钩子:

引自官方角色网站:

  
      输入或输出绑定值更改时
  • ngOnChanges被调用
  •   在第一个ngOnInit 之后调用
  • ngOnChanges   

所以你应该使用ngOnInit如果初始化处理依赖于组件的绑定(例如用@Input定义的组件参数),否则构造函数就足够了......

答案 5 :(得分:29)

简短的回答是,

[WARNING] Failed startup of context o.e.j.m.p.JettyWebAppContext@34cf294c{/vedc- web,[file:///D:/VEDC-TEST/vedc-web/src/main/webapp/, jar:file:///C:/Users/Saufi/ .m2/repository/org/webjars/Eonasdan-bootstrap-datetimepicker/4.15.35/Eonasdan-bo otstrap-datetimepicker-4.15.35.jar!/META-INF/resources, jar:file:///C:/Users/Sau fi/.m2/repository/org/webjars/bootstrap/3.3.6/bootstrap-3.3.6.jar!/META-INF/reso urces, jar:file:///C:/Users/Saufi/.m2/repository/org/webjars/respond/1.4.2/respo nd-1.4.2.jar!/META-INF/resources, jar:file:///C:/Users/Saufi/.m2/repository/org/ webjars/datatables/1.10.9/datatables-1.10.9.jar!/META-INF/resources, jar:file:// /C:/Users/Saufi/.m2/repository/org/webjars/jquery/1.11.3/jquery-1.11.3.jar!/META -INF/resources, jar:file:///C:/Users/Saufi/.m2/repository/org/webjars/datatables -plugins/1.10.9/datatables-plugins-1.10.9.jar!/META-INF/resources, jar:file:///C :/Users/Saufi/.m2/repository/org/webjars/bower/bootstrap-wizard/1.0.0/bootstrap- wizard-1.0.0.jar!/META-INF/resources, jar:file:///C:/Users/Saufi/.m2/repository/ org/webjars/html5shiv/3.7.3/html5shiv-3.7.3.jar!/META-INF/resources, jar:file:// /C:/Users/Saufi/.m2/repository/org/webjars/momentjs/2.10.6/momentjs-2.10.6.jar!/ META-INF/resources, jar:file:///C:/Users/Saufi/.m2/repository/org/webjars/font-a wesome/4.5.0/font-awesome-4.5.0.jar!/META-INF/resources],STARTING}{file:///D:/VE DC-TEST/vedc-web/src/main/webapp/} java.lang.Exception: Timeout scanning annotations at org.eclipse.jetty.annotations.AnnotationConfiguration.scanForAnnotati ons(AnnotationConfiguration.java:574) at org.eclipse.jetty.annotations.AnnotationConfiguration.configure(Annot ationConfiguration.java:444) at org.eclipse.jetty.webapp.WebAppContext.configure(WebAppContext.java:4 85) at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.jav a:1330) at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandle r.java:772) at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContex tHandler.java:259) at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:511 ) at org.eclipse.jetty.maven.plugin.JettyWebAppContext.doStart(JettyWebApp Context.java:403) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLife Cycle.java:68) at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLi feCycle.java:132) at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(Container LifeCycle.java:114) at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHand ler.java:61) at org.eclipse.jetty.server.handler.ContextHandlerCollection.doStart(Con textHandlerCollection.java:161) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLife Cycle.java:68) at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLi feCycle.java:132) at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(Container LifeCycle.java:114) at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHand ler.java:61) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLife Cycle.java:68) at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLi feCycle.java:132) at org.eclipse.jetty.server.Server.start(Server.java:405) at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(Container LifeCycle.java:106) at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHand ler.java:61) at org.eclipse.jetty.server.Server.doStart(Server.java:372) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLife Cycle.java:68) at org.eclipse.jetty.maven.plugin.AbstractJettyMojo.startJetty(AbstractJ ettyMojo.java:457) at org.eclipse.jetty.maven.plugin.AbstractJettyMojo.execute(AbstractJett yMojo.java:328) at org.eclipse.jetty.maven.plugin.JettyRunMojo.execute(JettyRunMojo.java :170) at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(Default BuildPluginManager.java:134) at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor .java:207) at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor .java:153) at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor .java:145) at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProje ct(LifecycleModuleBuilder.java:116) at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProje ct(LifecycleModuleBuilder.java:80) at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThre adedBuilder.build(SingleThreadedBuilder.java:51) at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(Lifecycl eStarter.java:128) at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:307) at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:193) at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:106) at org.apache.maven.cli.MavenCli.execute(MavenCli.java:863) at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:288) at org.apache.maven.cli.MavenCli.main(MavenCli.java:199) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl. java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces sorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Laun cher.java:289) at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.jav a:229) at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(La uncher.java:415) at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java: 356) [INFO] Started ServerConnector@49ec6a9f{HTTP/1.1,[http/1.1]}{0.0.0.0:8088} [INFO] Started @153457ms [INFO] Started Jetty Server Constructor是构建组件时的constructor次运行( by deafult )。当您创建类的default method时,也会调用an instance。换句话说,当调用组件constructor(default method)时,调用其中编写的相关代码。基本上并且通常在constructed or/and an instance is created constructor(default method)中,当构造组件以供进一步使用时,它用于注入诸如Angular2之类的东西。

services :ngOnInit是组件的生命周期挂钩,它在初始化组件后OnInit之后首先运行。

因此,首先调用构造函数,然后在构造函数方法之后调用Oninit。

<强> boot.ts

constructor(default method)

资源: LifeCycle hook

您可以查看 small demo ,其中显示了这两项内容的实施。

答案 6 :(得分:28)

我将在上面的解释中添加一个重要的内容,并解释当您必须使用["1", "3", "5", "7"] 时。

如果您正在通过例如操作组件的DOM进行操作 ViewChildren ContentChildren ElementRef ,您的原生元素在构造函数阶段将无法使用。

但是,由于ngOnInit在创建组件并且已经调用了检查(ngOnInit)后发生,因此您可以在此时访问DOM。

ngOnChanges

答案 7 :(得分:17)

为了测试这个,我写了这段代码,借鉴NativeScript Tutorial

<强> 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 ***  

答案 8 :(得分:16)

构造函数和ngOnInit之间的主要区别在于ngOnInitlifecycle hook并在构造函数之后运行。组件插值模板和输入初始值在构造函数中不可用,但它们在ngOnInit中可用。

实际差异是ngOnInit如何影响代码的结构。大多数初始化代码都可以移动到ngOnInit - ,只要这不会创建竞争条件

构造函数反模式

大量的初始化代码使得构造函数方法难以扩展,读取和测试。

将初始化逻辑与类构造函数分离的常用方法是将其移动到另一个方法,如init

class Some {
  constructor() {
    this.init();
  }

  init() {...}
}

ngOnInit可以在组件和指令中实现此目的:

constructor(
  public foo: Foo,
  /* verbose list of dependencies */
) {
  // time-sensitive initialization code
  this.bar = foo.getBar();
}

ngOnInit() {
  // rest of initialization code
}

依赖注入

Angular中类构造函数的主要作用是依赖注入。构造函数也用于TypeScript中的DI注释。几乎所有依赖项都被指定为类实例的属性。

平均组件/指令构造函数已经足够大了,因为它可以由于依赖性而具有多行签名,将不必要的初始化逻辑放置到构造函数体对反模式的贡献。

异步初始化

异步初始化构造函数通常可以被认为是反模式并且有异味,因为类实例化在异步例程之前完成,这可能会创建竞争条件。如果不是这样,那么ngOnInit和其他生命周期钩子就是更好的地方,特别是因为它们可以从async语法中受益:

constructor(
  public foo: Foo,
  public errorHandler: ErrorHandler
) {}

async ngOnInit() {
  try {
    await this.foo.getBar();
    await this.foo.getBazThatDependsOnBar();
  } catch (err) {
    this.errorHandler.handleError(err);
  }
}

如果存在竞争条件(包括组件不应出现在初始化错误中),则应在组件实例化之前进行异步初始化例程,并将其移至父组件,路由器保护等。

单元测试

ngOnInit比构造函数更灵活,并为this answer中详细解释的单元测试提供了一些好处。

考虑到在单元测试中组件编译时不会自动调用ngOnInit,在组件实例化后可以对ngOnInit中调用的方法进行间谍或模拟。

在特殊情况下,ngOnInit可以完全存根,以便为其他组件单元提供隔离(例如,某些模板逻辑)。

继承

子类只能扩充构造函数,而不能替换它们。

由于this之前无法引用super(),因此会限制初始化优先级。

考虑到Angular组件或指令使用ngOnInit进行时间不敏感的初始化逻辑,子类可以选择是否调用super.ngOnInit()以及何时:

ngOnInit() {
  this.someMethod();
  super.ngOnInit();
}

单独使用构造函数无法实现。

答案 9 :(得分:14)

与许多其他语言一样,您可以在类级别,构造函数或方法中初始化变量。由开发人员决定在他们的特定情况下最好的是什么。但下面列出了决定时的最佳实践。

班级变量

通常,您将在此处声明将在其余部分中使用的所有变量。如果值不依赖于任何其他值,则可以初始化它们,或者如果它们不会更改,则使用const关键字创建常量。

export class TestClass{
    let varA: string = "hello";
}

构造

通常,最佳做法是不在构造函数中执行任何操作,只将其用于将要注入的类。大多数情况下,构造函数应如下所示:

   constructor(private http: Http, private customService: CustomService) {}

这将自动创建类级别变量,因此您无需手动操作即可访问customService.myMethod()

NgOnInit

NgOnit是Angular 2框架提供的生命周期钩子。您的组件必须实现OnInit才能使用它。在调用构造函数并初始化所有变量之后调用此生命周期钩子。你的大部分初始化应该放在这里。您将确信Angular已正确初始化您的组件,并且您可以在OnInit中开始执行所需的逻辑,而不是在组件未正确加载时执行操作。

这是一张详细说明所调用内容顺序的图像:

enter image description here

https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html

TLDR

如果您正在使用Angular 2框架并且需要与某些生命周期事件进行交互,请使用框架提供的方法来避免问题。

答案 10 :(得分:12)

以上答案并没有真正回答原问题的这一方面:什么是生命周期钩子?我花了一段时间才明白这意味着什么,直到我这样想。

1)说你的组件是人。人类的生活包括许多生活阶段,然后我们就会过期。

2)我们的人体成分可能具有以下生命周期脚本:出生,婴儿,小学,青年成人,中年成人,成年人,死亡,处置。

3)假设你想要一个创建孩子的功能。为了防止这种情况变得复杂,而且相当幽默,你希望你的功能只能在人体成分生命的青年成人阶段被调用。因此,您开发的组件仅在父组件处于Young Adult阶段时才处于活动状态。钩子通过发出生命阶段的信号并让你的组件对其起作用来帮助你做到这一点。

有趣的东西。如果你让你的想象力去实际编写这样的东西,它会变得复杂,有趣。

答案 11 :(得分:7)

构造函数 是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");
     }
}

&#34; ConstructorTest&#34; class在下面实例化;所以它在内部调用 构造函数(所有这些都发生在JavaScript(es6)no Angular)。

new CONSTRUCTORTEST();

这就是当Angular完成组件初始化时,Angular.ngOnInit中存在 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();
必要时,Angular会调用

ngOnInit,如下所示:

instance.ngOnInit();

但你可能会问为什么我们在Angular中使用构造函数?

答案是 依赖注入 。如前所述,当实例化类时(在通过Angular调用ngOnInit之前),JavaScript引擎会立即调用构造函数,因此打字稿帮助我们获取构造函数中定义的依赖项类型,最后告诉Angular我们要在该特定组件中使用哪种类型的依赖项。

答案 12 :(得分:7)

这里要注意两件事:

  1. 只要为该类创建了一个对象,就会调用构造函数。
  2. ngOnInit在创建组件后调用。
  3. 两者都有不同的可用性。

答案 13 :(得分:4)

构造 ES6类(或本例中为TypeScript)上的构造函数方法是类本身的一个特性,而不是Angular特性。当调用构造函数时,它不受Angular的控制,这意味着当Angular完成组件的初始化时,它不是一个合适的钩子让你知道。 JavaScript引擎直接调用构造函数而不是Angular。这就是创建ngOnInit(和AngularJS中的$ onInit)生命周期钩子的原因。考虑到这一点,有一个适合使用构造函数的方案。这是我们想要利用依赖注入的时候 - 主要是为了将依赖关系“连接”到组件中。

由于构造函数是由JavaScript引擎初始化的,TypeScript允许我们告诉Angular我们需要针对特定​​属性映射哪些依赖项。

ngOnInit 纯粹是为了给我们一个信号,表明Angular已经完成了组件的初始化。

此阶段包括针对我们可能绑定到组件本身的属性进行Change Detection的第一次传递 - 例如使用@Input()装饰器。

由于这个原因,@ ingput()属性在ngOnInit中可用,但在构造函数中未定义,按设计

答案 14 :(得分:4)

constructor()是组件生命周期中的默认方法,用于依赖项注入。构造函数是一个Typescript特征。

在第一次ngOnChanges之后调用构造函数和ngOnInit之后调用

ngOnInit()

即。构造() - &GT; ngOnChanges() - &GT; ngOnInit()

如上所述,当输入或输出绑定值发生变化时,会调用ngOnChanges()。

答案 15 :(得分:4)

两种方法都有不同的目标/责任。构造函数的任务(这是一种语言支持的特性)是为了确保表示不变量成立。否则声明通过向成员提供正确的值来确保实例有效。由开发人员决定什么是正确的&#39;装置

onInit()方法(角度概念)的任务是允许对正确的对象(表示不变)进行方法调用。每个方法应该确保在方法终止时表示不变量保持不变。

构造函数应该用于创建&#39;更正&#39;对象,onInit方法使您有机会在定义良好的实例上调用方法调用。

答案 16 :(得分:2)

构造函数是第一个,有时@input数据为null时会发生! 因此我们使用Constructor进行声明服务,然后ngOnInit发生。 构造器示例:

1500000

onInit示例:

 constructor(translate: TranslateService, private oauthService: OAuthService) {
    translate.setDefaultLang('En');
        translate.use('En');}

我认为onInit类似于winForm中的InitialComponents()。

答案 17 :(得分:1)

在角度生命周期中

1)Angular进样器检测构造函数参数(&#39; s)并实例化类。

2)下一个角度呼叫生命周期

Angular Lifecycle Hooks

ngOnChanges - &gt;调用指令参数绑定。

ngOnInit - &gt;开始角度渲染...

使用角度生命周期状态调用其他方法。

答案 18 :(得分:1)

当Angular“实例化/构造”组件时,将调用constructorngOnInit方法是一个钩子,代表组件生命周期的初始化部分。 一个好的做法是仅将其用于服务注入

constructor(private 
    service1: Service1,
    service2: Service2
){};

即使有可能,您也不应该在内部做一些“工作”。 如果要启动组件“初始化”时必须执行的某些操作,请使用ngOnInit

ngOnInit(){
    service1.someWork();
};

此外,涉及输入属性的操作来自父组件,无法在构造器中执行。 应将它们放在ngOnInit方法中或其他钩子中。 与视图(DOM)相关的元素相同,例如, viewchild元素

@Input itemFromParent: string;
@ViewChild('childView') childView;

constructor(){
    console.log(itemFromParent); // KO
    // childView is undefined here
};

ngOnInit(){
    console.log(itemFromParent); // OK
    // childView is undefined here, you can manipulate here
};

答案 19 :(得分:1)

我找到了答案,并尝试将其翻译成英文:  即使在技术面试中,这个问题仍然出现。实际上,两者之间有很大的相似之处,但也存在一些差异。

  • 构造函数是ECMAScript的一部分。另一方面,ngOnInit()是角度的概念。

  • 即使不使用Angular,我们也可以在所有类中调用构造函数

  • LifeCycle:构造函数在ngOnInt()之前调用

  • 在构造函数中,我们无法调用HTML元素。但是,在ngOnInit()中可以。

  • 通常,服务调用是在ngOnInit()中,而不是在构造函数中

    来源:http://www.angular-tuto.com/Angular/Component#Diff

答案 20 :(得分:1)

@Input

通信机制是作为以下更改检测阶段的一部分处理的,因此输入绑定在构造函数中不可用。

答案 21 :(得分:1)

Constructor是ES6的一部分,打字稿也使用es6语法,现在也使用es7,因此您可以利用打字稿将编译为es5 / es4的高级功能(根据您的定义)为旧浏览器提供支持

ngOnInIt是角度的生命周期挂钩。在初始化组件时进行初始化。 (考虑到这是任何新生命的诞生)

使用ngOnInIt与构造函数进行比较是明智的,因为您还有另一个生命周期挂钩,例如ngOnDestory(将其视为任何生命的死亡)。在这里,您可以取消订阅任何可观察到的东西,以防止任何内存泄漏。

万一有任何疑问可以对此答案发表评论。

答案 22 :(得分:0)

constructor()用于执行依赖注入。

ngOnInit()ngOnChanges()ngOnDestroy()等是生命周期方法。在ngOnChanges()之前,ngOnInit()将是第一个被调用的,当绑定属性的值发生更改时,如果没有更改,则不会调用它。删除组件时会调用ngOnDestroy()。要使用它,OnDestroy需要由班级implement

答案 23 :(得分:0)

实际上,ngOnInit()有两个主要原因:

1)在构造后不久执行复杂的初始化。

2)要在Angular设置输入属性之后设置组件。

经验丰富的开发人员同意,组件应该便宜且安全地构建。

Angular团队负责人Misko Hevery解释了为什么应该避免复杂的构造方法逻辑。

不要在组件构造函数中获取数据。您不必担心在测试中创建新组件或决定显示它之前,它会尝试与远程服务器联系。构造函数只需要将初始局部变量设置为简单值即可。

ngOnInit()是组件获取其初始数据的好地方。

还请记住,直到构造后才设置指令的数据绑定输入属性。如果您需要基于这些属性初始化指令,那将是一个问题。它们将在ngOnInit()运行时设置。

ngOnChanges()方法是您访问这些属性的第一个机会。 Angular在ngOnInit()之前调用ngOnChanges(),之后多次调用。只会调用一次ngOnInit()。

创建组件后,您可以依靠Angular来调用ngOnInit()方法。那就是繁重的初始化逻辑所属的地方。

答案 24 :(得分:0)

构造函数

每个类都有构造函数,构造函数不是特定于Angular的,而是从面向对象设计派生的概念。构造函数创建组件类的实例。

OnInit

ngOnInit函数是Angular组件的生命周期方法之一。 Angular组件中的生命周期方法(或挂钩)使您可以在组件生命周期的不同阶段运行一段代码。 与构造函数方法不同,ngOnInit方法来自组件需要实现才能使用此方法的Angular接口(OnInit)。创建组件后不久,就会调用ngOnInit方法。

答案 25 :(得分:0)

实例化类时,将执行构造函数。它与角度无关。这是Javascript的功能,Angular无法控制它

ngOnInit是Angular专用的,当Angular使用其所有输入属性初始化组件时会调用

@Input属性在ngOnInit生命周期挂钩下可用。这将帮助您完成一些初始化工作,例如从后端服务器获取数据等以在视图中显示

@Input属性在构造函数中显示为未定义

答案 26 :(得分:0)

constructor() 可以接受参数并且可以用于依赖注入或者constructor() 用于添加服务对象。

构造函数在ngOnint()之前被调用;

ngOnInit() 用于通过必要的服务函数调用来操作组件,或者通常在 ngOnInit() 而非构造函数中调用服务

答案 27 :(得分:0)

Constructor是Typescript类提供的默认方法,专用于初始化类成员,一般用于依赖注入服务,如上面的示例代码< /strong>,或者定时器初始化,socket连接初始化

export class AppComponent {
  title = 'angular-fork-join';
  constructor(private http: HttpClient) {}

ngOnInit:是Angular提供的组件初始化时调用的生命周期钩子,专门用于业务逻辑、数据初始化、API调用等,示例代码演示API调用:

export class HomeComponent implements OnInit {

  products = [];

  constructor(private dataService: DataService) { }

  ngOnInit() {

    this.dataService.sendGetRequest().subscribe((data: any[])=>{
      console.log(data);
      this.products = data;
    })  
  }

} 

答案 28 :(得分:-1)

构造函数是在构建组件(或其他类)时执行的功能。

ngOnInit 是属于组件生命周期方法组的函数,它们在组件的不同时刻执行(这就是为什么要命名生命周期)。这是所有这些的列表:

enter image description here 构造函数将在任何生命周期函数之前执行。