Sự khác biệt giữa Con Contor và ngOnInit


1075

Angular cung cấp móc vòng đời ngOnInittheo mặc định.

Tại sao nên ngOnInitsử dụng, nếu chúng ta đã có một constructor?


11
này, hãy xem câu trả lời của tôi giải thích sự khác biệt từ quan điểm hoạt động bên trong của Angular
Max Koretskyi


1
@MaximKoretskyi, liên kết của bạn đã chết.
Yash Capoor

Câu trả lời:


1111

Các Constructorlà một phương pháp mặc định của lớp được thực hiện khi lớp được khởi tạo và đảm bảo khởi động đúng đắn của các lĩnh vực trong lớp và lớp con của nó. Angular, hoặc phụ thuộc tốt hơn (DI), phân tích các tham số của hàm tạo và khi nó tạo một thể hiện mới bằng cách gọi new MyClass()nó cố gắng tìm các nhà cung cấp khớp với các loại tham số của hàm tạo, giải quyết chúng và chuyển chúng đến hàm tạo như

new MyClass(someArg);

ngOnInit là một cái móc vòng đời được gọi bởi Angular để chỉ ra rằng Angular đã hoàn thành việc tạo ra thành phần.

Chúng tôi phải nhập OnInitnhư thế này để sử dụng nó (thực tế việc triển khai OnInitkhông bắt buộc nhưng được coi là thực hành tốt):

import { Component, OnInit } from '@angular/core';

sau đó để sử dụng làm cho chúng ta phương thức OnInit, chúng ta phải thực hiện lớp như thế này:

export class App implements OnInit {
  constructor() {
     // Called first time before the ngOnInit()
  }

  ngOnInit() {
     // Called after the constructor and called  after the first ngOnChanges() 
  }
}

Triển khai giao diện này để thực thi logic khởi tạo tùy chỉnh sau khi các thuộc tính ràng buộc dữ liệu của lệnh của bạn đã được khởi tạo. ngOnInit được gọi ngay sau khi các thuộc tính ràng buộc dữ liệu của lệnh được kiểm tra lần đầu tiên và trước khi bất kỳ con nào của nó được kiểm tra. Nó chỉ được gọi một lần khi lệnh được khởi tạo.

Chủ yếu chúng tôi sử dụng ngOnInitcho tất cả các khởi tạo / khai báo và tránh các công cụ để làm việc trong hàm tạo. Hàm tạo chỉ nên được sử dụng để khởi tạo các thành viên lớp nhưng không nên thực hiện "công việc" thực tế.

Vì vậy, bạn nên sử dụng constructor()để thiết lập Dependency Injection và không nhiều thứ khác. ngOnInit () là nơi tốt hơn để "bắt đầu" - đó là nơi / khi các ràng buộc của các thành phần được giải quyết.

Để biết thêm thông tin tham khảo tại đây:


62
Chính xác, hầu hết (hoặc thậm chí tất cả) các ngôn ngữ dựa trên lớp đều có các bộ điều khiển để đảm bảo thứ tự khởi tạo thích hợp, đặc biệt là các lớp mở rộng các lớp khác, nơi một số vấn đề khá khó có thể xảy ra, như các trường cuối cùng (không biết TS có chúng không) và tương tự. Trình xây dựng không liên quan đến Angular2, chúng là một tính năng TypeScript. Móc vòng đời được Angular gọi sau khi một số khởi tạo diễn ra hoặc khi một số sự kiện xảy ra để cho phép thành phần hành động trong một số tình huống nhất định và cho nó cơ hội thực hiện một số nhiệm vụ vào thời điểm thích hợp.
Günter Zöchbauer

12
Có một trích dẫn khối trong angular.io/docs/ts/latest/guide/server-c truyền thông.html cũng giải thích điều này: "Các thành phần dễ kiểm tra và gỡ lỗi hơn khi các hàm tạo của chúng đơn giản và tất cả đều hoạt động thực sự (đặc biệt là gọi một máy chủ từ xa) được xử lý theo một phương pháp riêng biệt. " - Trong trường hợp này phương thức đó là ngOnInit ()
yoonjesung

3
là một cái móc vòng đời được gọi bởi Angular2 để chỉ ra rằng Angular đã hoàn thành việc tạo ra thành phần. - đó không phải là chính xác. nó báo hiệu rằng nó đã khởi tạo các ràng buộc. Các thành phần được tạo ra trước đó. Xem câu trả lời của tôi
Max Koretskyi

22
Như với tất cả các "thực hành tốt nhất", tôi nghĩ rằng cũng sẽ là một ý tưởng tốt để giải thích lý do tại sao bạn không nên làm "công việc" trong hàm tạo. Bài viết này do nhóm nghiên cứu dẫn đầu kiễu góc là dày đặc nhưng có thể giúp: misko.hevery.com/code-reviewers-guide/... Ngoài ra, ít quan trọng nên được đặt trên các câu thần chú cần thiết để thực hiện OnInit (điều này rất dễ dàng để tìm thấy) và nhiều hơn nữa trên thực tế quan trọng là các ràng buộc dữ liệu không có sẵn trong hàm tạo.
Reikim

2
Nếu chế độ nghiêm ngặt là đúng trong tsconfig.jsontệp như thế "strict": true, thì bạn phải khởi tạo các thành viên lớp trong constructor, chứ không phải ngOnitnhư thế FormGroup.
Rohit Sharma

172

Bài viết Sự khác biệt cơ bản giữa Người xây dựng và ngOnInit trong Angular khám phá sự khác biệt từ nhiều quan điểm. Câu trả lời này cung cấp giải thích khác biệt quan trọng nhất liên quan đến quá trình khởi tạo thành phần cũng cho thấy sự khác biệt trong cách sử dụng.

Quá trình bootstrap góc bao gồm hai giai đoạn chính:

  • xây dựng thành phần cây
  • chạy phát hiện thay đổi

Hàm tạo của thành phần được gọi khi Angular xây dựng cây thành phần. Tất cả các móc vòng đời được gọi là một phần của việc phát hiện thay đổi đang chạy.

Khi Angular xây dựng các thành phần cây, bộ tiêm mô-đun gốc đã được cấu hình để bạn có thể tiêm bất kỳ phụ thuộc toàn cục nào. Ngoài ra, khi Angular khởi tạo một lớp thành phần con, trình tiêm cho thành phần cha mẹ cũng đã được thiết lập để bạn có thể tiêm các nhà cung cấp được xác định trên thành phần cha mẹ bao gồm chính thành phần cha mẹ. Các hàm tạo thành phần là phương thức duy nhất được gọi trong ngữ cảnh của trình tiêm, vì vậy nếu bạn cần bất kỳ sự phụ thuộc nào thì đó là nơi duy nhất có được các phụ thuộc đó.

Khi Angular bắt đầu phát hiện thay đổi, cây thành phần được xây dựng và các hàm tạo cho tất cả các thành phần trong cây đã được gọi. Ngoài ra, các nút mẫu của mọi thành phần được thêm vào DOM. Cơ @Inputchế giao tiếp được xử lý trong quá trình phát hiện thay đổi, do đó bạn không thể mong đợi có các thuộc tính có sẵn trong hàm tạo. Nó sẽ có sẵn sau ngOnInit.

Hãy xem một ví dụ nhanh. Giả sử bạn có mẫu sau:

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

Vì vậy, Angular bắt đầu bootstrapping ứng dụng. Như tôi đã nói, đầu tiên nó tạo các lớp cho mỗi thành phần. Vì vậy, nó gọi MyAppComponentconstructor. Nó cũng tạo ra một nút DOM là thành phần chủ của my-appthành phần. Sau đó, nó tiến hành tạo một phần tử máy chủ cho hàm tạo child-compvà gọi hàm ChildComponenttạo. Ở giai đoạn này, nó không thực sự liên quan đến iràng buộc đầu vào và bất kỳ móc vòng đời nào. Vì vậy, khi quá trình này kết thúc, Angular kết thúc với các khung nhìn thành phần sau:

MyAppView
  - MyApp component instance
  - my-app host element data
       ChildCompnentView
         - ChildComponent component instance
         - child-comp host element data  

Chỉ sau đó chạy phát hiện thay đổi và cập nhật các ràng buộc cho my-appvà các cuộc gọi ngOnInittrên lớp MyAppComponent. Sau đó, nó tiến hành cập nhật các ràng buộc cho child-compvà gọi ngOnInittrên lớp ChildComponent.

Bạn có thể thực hiện logic khởi tạo của mình trong hàm tạo hoặc ngOnInittùy thuộc vào những gì bạn cần có sẵn. Ví dụ bài viết Dưới đây là cách lấy ViewContainerRef trước khi truy vấn @ViewChild được đánh giá cho thấy loại logic khởi tạo nào có thể được yêu cầu để được thực hiện trong hàm tạo.

Dưới đây là một số bài viết sẽ giúp bạn hiểu rõ hơn về chủ đề:


33
đây sẽ là câu trả lời được chấp nhận nó thực sự giải thích TẠI SAO thay vì lặp lại câu thần chú và nêu rõ the constructor should only be used to inject dependencies.
Stavm

1
@ yannick1976, cảm ơn! Kiểm tra các bài viết được tham khảo
Max Koretskyi

@flobacca, bạn có thể vui lòng viết lại câu hỏi không, thật khó để hiểu những gì bạn đang hỏi
Max Koretskyi

Vui long sửa cho tôi nêu tôi sai. Tôi hiểu cây thành phần được xây dựng đầu tiên và sau đó thay đổi quá trình phát hiện. Bạn đã viết hàm tạo AppComponent đầu tiên được gọi (cùng với các phụ thuộc đã giải quyết) sau đó hàm tạo ChildComponent được gọi (cùng với các phụ thuộc) sau đó nhập các ràng buộc cho AppComponent và sau đó OnInit được gọi. Nhưng mối quan tâm của tôi là nếu tôi thêm móc vòng đời để cả hai thành phần dòng chảy là AppComponentConstructor - -> AppComponentOnInit - → ChildComponentConstructor - → ChildComponentOnInit Tại sao AppComponentOnInit đang được gọi trước khi ChildComponentConstructor
user2485435

1
@MaxKoretskyiakaWizard bạn đã đúng. Tôi đã thực hiện một số sai lầm trong thiết lập ứng dụng của tôi. nó hoạt động như mô tả của bạn. angular-c7zjsx.stackblitz.io
user2485435

94

Tôi nghĩ rằng ví dụ tốt nhất sẽ được sử dụng dịch vụ. Giả sử tôi muốn lấy dữ liệu từ máy chủ của mình khi thành phần của tôi được 'Kích hoạt'. Giả sử tôi cũng muốn thực hiện một số điều bổ sung cho dữ liệu sau khi tôi nhận được nó từ máy chủ, có thể tôi gặp lỗi và muốn đăng nhập dữ liệu khác.

Nó thực sự dễ dàng với ngOnInit qua một hàm tạo, nó cũng giới hạn số lượng lớp gọi lại mà tôi cần thêm vào ứng dụng của mình.

Ví dụ:

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


}

với hàm tạo của tôi, tôi chỉ có thể gọi _userService của mình và điền vào user_list của mình, nhưng có lẽ tôi muốn làm thêm một số thứ với nó. Giống như đảm bảo mọi thứ đều là chữ hoa, tôi không hoàn toàn chắc chắn làm thế nào dữ liệu của tôi được thông qua.

Vì vậy, nó làm cho nó dễ dàng hơn nhiều để sử dụng 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();
    };


}

Nó làm cho nó dễ nhìn hơn nhiều, và vì vậy tôi chỉ gọi hàm của mình trong thành phần của mình khi tôi khởi tạo thay vì phải đào nó ở một nơi khác. Thực sự nó chỉ là một công cụ khác mà bạn có thể sử dụng để giúp đọc và sử dụng dễ dàng hơn trong tương lai. Ngoài ra tôi thấy thực tế rất tệ khi đặt các lệnh gọi hàm trong hàm tạo!


Ví dụ của bạn có thể được đơn giản hóa nếu bạn chỉ đặt user_list thành Observable. Angular2 có đường ống không đồng bộ, vì vậy sẽ không có vấn đề gì ở đó.
DarkNeuron

@Morgan, chỉ cho tôi học một điều nhỏ ở đây, tại sao trước tiên bạn tạo một hàm getUsersvà sau đó chèn nó vào ngOnInit? Có phải nó không ít mã để chỉ viết nó trong ngOnInit? Tôi là jsut tự hỏi tại sao mọi người làm theo cách này? Có phải vì vậy mà bạn có thể sử dụng lại mã nếu bạn cũng muốn? Cảm ơn.
Alfa Bravo

31
Như đã thấy trong câu trả lời dưới đây, điều này không có gì khác biệt nếu nó nằm trong hàm tạo. Đây không phải là một câu trả lời thực sự cho mục đích.
Jimmy Kane

8
Tôi không thấy làm thế nào điều này trả lời câu hỏi cả. Tại sao bạn không thể đặt mã vào constructor?
CodyBugstein

1
@Morgan tại sao có thể không chỉ cần làmconstructor(private _userService: UserService){ this.getUsers(); };
Ashley

82

OK, trước hết ngOnInitlà một phần của vòng đời Angular , trong khi constructorlà một phần của lớp JavaScript ES6 , vì vậy sự khác biệt chính bắt đầu từ ngay tại đây! ...

Nhìn vào biểu đồ dưới đây tôi tạo ra cho thấy vòng đời của Angular.

ngOnInit vs constructor

Trong Angular2 +, chúng tôi sử dụng constructorđể làm điều đó DI(Dependency Injection)cho chúng tôi, trong khi ở Angular 1, điều đó đã xảy ra thông qua việc gọi phương thức String và kiểm tra xem sự phụ thuộc nào đã được đưa vào.

Như bạn thấy trong sơ đồ trên, ngOnInitsẽ xảy ra sau khi hàm tạo sẵn sàng ngOnChnagesvà được kích hoạt sau khi thành phần sẵn sàng cho chúng ta. Tất cả các khởi tạo có thể xảy ra trong giai đoạn này, một mẫu đơn giản là tiêm dịch vụ và khởi tạo nó trên init.

OK, tôi cũng chia sẻ một mã mẫu để bạn xem, xem cách chúng tôi sử dụng ngOnInitconstructortrong mã dưới đây:

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

1
Cảm ơn. đây sẽ là câu trả lời tốt nhất
Don Dilanga

58

Cái đầu tiên (constructor) có liên quan đến khởi tạo lớp và không liên quan gì đến Angular2. Tôi có nghĩa là một constructor có thể được sử dụng trên bất kỳ lớp nào. Bạn có thể đặt vào đó một số xử lý khởi tạo cho thể hiện mới được tạo.

Cái thứ hai tương ứng với móc vòng đời của các thành phần Angular2:

Trích dẫn từ trang web chính thức của angular:

  • ngOnChanges được gọi khi giá trị ràng buộc đầu vào hoặc đầu ra thay đổi
  • ngOnInit được gọi sau đầu tiên ngOnChanges

Vì vậy, bạn nên sử dụng ngOnInitnếu quá trình khởi tạo phụ thuộc vào các ràng buộc của thành phần (ví dụ: các tham số thành phần được xác định @Input), nếu không thì hàm tạo sẽ đủ ...


49

Tôi sẽ chỉ thêm một điều quan trọng đã bị bỏ qua trong các giải thích ở trên và giải thích khi bạn PHẢI sử dụng ngOnInit.

Nếu bạn đang thực hiện bất kỳ thao tác nào của DOM của thành phần thông qua ví dụ ViewChildren , ContentChildren hoặc ElementRef , các phần tử nguyên gốc của bạn sẽ không khả dụng trong giai đoạn xây dựng.

Tuy nhiên, kể từ khi ngOnInitxảy ra một khi thành phần đã được tạo và kiểm tra ( ngOnChanges) đã được gọi, bạn có thể truy cập DOM tại thời điểm này.

export class App implements OnInit, AfterViewInit, AfterContentInit {
  @Input() myInput: string;
  @ViewChild() myTemplate: TemplateRef<any>;
  @ContentChild(ChildComponent) myComponent: ChildComponent; 

  constructor(private elementRef: ElementRef) {
     // this.elementRef.nativeElement is undefined here
     // this.myInput is undefined here
     // this.myTemplate is undefined here
     // this.myComponent is undefine here
  }

  ngOnInit() {
     // this.elementRef.nativeElement can be used from here on
     // value of this.myInput is passed from parent scope
     // this.myTemplate and this.myComponent are still undefined
  }
  ngAfterContentInit() {
     // this.myComponent now gets projected in and can be accessed
     // this.myTemplate is still undefined
  }

  ngAfterViewInit() {
     // this.myTemplate can be used now as well
  }
}

3
Không. Đối với @ViewChildrencụ thể, bạn cần sử dụng ngAfterViewInitphương pháp. Xem tại đây: stackoverflow.com/questions/46314734/
Mạnh

1
Cảm ơn, @AsoodAsItGets đã chỉ ra điều đó. Bây giờ tôi đã cải thiện câu trả lời
Miroslav Jonas

38

Câu trả lời ngắn gọn và đơn giản sẽ là,

Constructor: constructorlà một default methodlần chạy ( bởi điếc ) khi thành phần đang được xây dựng. Khi bạn tạo ra an instancemột lớp thời gian cũng constructor(default method)sẽ được gọi. Vì vậy, nói cách khác, khi thành phần đang được constructed or/and an instance is created constructor(default method)gọi và mã có liên quan được viết bên trong được gọi. Về cơ bản và nói chung trong Angular2nó được sử dụng để tiêm những thứ như serviceskhi thành phần đang được xây dựng để sử dụng tiếp.

OnInit: ngOnInit là hook vòng đời của thành phần chạy trước sau constructor(default method)khi thành phần được khởi tạo.

Vì vậy, constructor của bạn sẽ được gọi trước và Oninit sẽ được gọi sau sau phương thức constructor.

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() 
   }
}

Tài nguyên: Móc vòng đời

Bạn có thể kiểm tra bản demo nhỏ này cho thấy việc thực hiện cả hai điều.


5
Tôi nghĩ rằng "constructor là một cái gì đó chạy hoặc được gọi khi thành phần được khởi tạo." là sai lệch. Hàm tạo là một tính năng của lớp không phải của thành phần. Tôi muốn nói rằng thể hiện của lớp chỉ trở thành một thành phần sau khi hàm tạo được gọi Angular đã khởi tạo nó.
Günter Zöchbauer

Có thay đổi tuyên bố bạn có thể kiểm tra ngay bây giờ.
micronyks 3/03/2016

1
Hmm, IMHO vẫn là "hàm tạo (phương thức mặc định) giống như cái gì đó chạy hoặc được gọi khi thành phần được xây dựng." Nó không chỉ được gọi khi một thành phần được xây dựng mà còn cho các dịch vụ hoặc khi mã giống như new MyClass()được thực thi. Tôi nghĩ thật sai lầm khi nói các nhà xây dựng là về các thành phần, chúng là về các lớp và khởi tạo các thể hiện của các lớp này. Một thành phần chỉ là một lớp như vậy. Nếu không, tôi nghĩ rằng đó là một câu trả lời tốt.
Günter Zöchbauer

2
Phải, chắc chắn rồi. Quên đề cập rằng khi bạn tạo một đối tượng của một lớp thì thời gian đó constructorsẽ được gọi. Nhưng câu trả lời này đã được viết trong bối cảnh angular2. Để biết câu trả lời tốt nhất, bạn phải biết những điều cơ bản về OOP. Tôi vẫn sẽ cập nhật câu trả lời.
micronyks 3/03/2016

@ GünterZöchbauer, tôi không nghĩ rằng đó là một khẳng định chính xác, đó là một tính năng của lớp không phải của thành phần . Từ quan điểm ngôn ngữ lập trình có, điều này là chính xác. Nhưng tôi có thể làm việc thành công với các thành phần mà không cần bất kỳ móc vòng đời nào cả. Nhưng tôi không thể làm việc với một thành phần mà không có nhà xây dựng nếu tôi cần DI vì đó là nơi duy nhất có thể tiêm được. Xem câu trả lời của tôi
Max Koretskyi

20

Giống như nhiều ngôn ngữ khác, bạn có thể khởi tạo các biến ở cấp độ lớp, hàm tạo hoặc một phương thức. Tùy thuộc vào nhà phát triển để quyết định điều gì là tốt nhất trong trường hợp cụ thể của họ. Nhưng dưới đây là danh sách các thực hành tốt nhất khi quyết định.

Biến cấp lớp

Thông thường, bạn sẽ khai báo tất cả các biến của bạn ở đây sẽ được sử dụng trong phần còn lại của thành phần. Bạn có thể khởi tạo chúng nếu giá trị không phụ thuộc vào bất cứ điều gì khác hoặc sử dụng từ khóa const để tạo hằng nếu chúng không thay đổi.

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

Constructor

Thông thường, cách tốt nhất là không làm gì trong hàm tạo và chỉ sử dụng nó cho các lớp sẽ được thêm vào. Hầu hết thời gian nhà xây dựng của bạn sẽ trông như thế này:

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

điều này sẽ tự động tạo các biến cấp độ lớp, vì vậy bạn sẽ có quyền truy cập customService.myMethod()mà không cần phải thực hiện thủ công.

NgOnInit

NgOnit là một cái móc vòng đời được cung cấp bởi khung Angular 2. Thành phần của bạn phải thực hiện OnInitđể sử dụng nó. Móc vòng đời này được gọi sau khi hàm tạo được gọi và tất cả các biến được khởi tạo. Phần lớn việc khởi tạo của bạn nên vào đây. Bạn sẽ chắc chắn rằng Angular đã khởi tạo chính xác thành phần của bạn và bạn có thể bắt đầu thực hiện bất kỳ logic nào bạn cần OnInitso với thực hiện khi thành phần của bạn chưa tải xong.

Dưới đây là hình ảnh chi tiết thứ tự của cái được gọi là:

nhập mô tả hình ảnh ở đây

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

TLD

Nếu bạn đang sử dụng khung Angular 2 và cần tương tác với các sự kiện vòng đời nhất định, hãy sử dụng các phương thức được cung cấp bởi khung này để tránh các vấn đề.


19

Để kiểm tra điều này, tôi đã viết mã này, mượn từ Hướng dẫn NativeScript :

người dùng

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;
  }

}

Bảng điều khiển đầu ra

JS: *** User class constructor property ***  
JS: *** User class constructor constructor ***  
JS: *** Login Component Constructor ***  
JS: *** User class constructor ngOnInit ***  
JS: *** Login Component ngOnInit ***  

18

Sự khác biệt chính giữa constructor và ngOnInitđó ngOnInithook vòng đời và chạy sau constructor. Mẫu nội suy thành phần và các giá trị ban đầu đầu vào không có sẵn trong hàm tạo, nhưng chúng có sẵn trong ngOnInit.

Sự khác biệt thực tế là cách ngOnInitảnh hưởng đến cách cấu trúc mã. Hầu hết các mã khởi tạo có thể được chuyển đến ngOnInit- miễn là điều này không tạo ra điều kiện cuộc đua .

Xây dựng antipotype

Một lượng đáng kể mã khởi tạo làm cho phương thức constructor khó mở rộng, đọc và kiểm tra.

Một công thức thông thường để tách logic khởi tạo khỏi hàm tạo của lớp là chuyển nó sang một phương thức khác như init:

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

  init() {...}
}

ngOnInit có thể phục vụ mục đích này trong các thành phần và chỉ thị:

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

ngOnInit() {
  // rest of initialization code
}

Phụ thuộc tiêm

Vai trò chính của các nhà xây dựng lớp trong Angular là tiêm phụ thuộc. Các hàm tạo cũng được sử dụng cho chú thích DI trong TypeScript. Hầu như tất cả các phụ thuộc được gán làm thuộc tính cho thể hiện của lớp.

Trình xây dựng thành phần / chỉ thị trung bình đã đủ lớn bởi vì nó có thể có chữ ký đa dòng do phụ thuộc, đưa logic nội tâm hóa không cần thiết vào phần thân của trình tạo đóng góp vào antipotype.

Khởi tạo không đồng bộ

Hàm tạo khởi tạo không đồng bộ thường có thể được coi là antipotype và có mùi vì quá trình khởi tạo lớp kết thúc trước khi thói quen không đồng bộ thực hiện và điều này có thể tạo ra các điều kiện chạy đua. Nếu không phải như vậy ngOnInitvà các móc vòng đời khác là nơi tốt hơn cho việc này, đặc biệt vì chúng có thể được hưởng lợi từ asynccú pháp:

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

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

Nếu có các điều kiện chủng tộc (bao gồm cả điều kiện mà một thành phần không nên xuất hiện trong lỗi khởi tạo), thì thói quen khởi tạo không đồng bộ sẽ diễn ra trước khi khởi tạo thành phần và được chuyển sang thành phần chính, bộ bảo vệ bộ định tuyến, v.v.

Kiểm tra đơn vị

ngOnInitlinh hoạt hơn một nhà xây dựng và cung cấp một số lợi ích cho thử nghiệm đơn vị được giải thích chi tiết trong câu trả lời này .

Xem xét việc ngOnInitkhông được gọi tự động khi biên dịch thành phần trong các thử nghiệm đơn vị, các phương thức được gọi trong ngOnInitcó thể bị theo dõi hoặc chế giễu sau khi khởi tạo thành phần.

Trong các trường hợp đặc biệt ngOnInitcó thể được đặt hoàn toàn để cung cấp sự cô lập cho các đơn vị thành phần khác (ví dụ, một số logic mẫu).

Di sản

Các lớp con chỉ có thể tăng cường các nhà xây dựng, không thể thay thế chúng.

thiskhông thể được giới thiệu trước super(), điều này đặt ra các hạn chế về ưu tiên khởi tạo.

Xem xét rằng thành phần hoặc chỉ thị Angular sử dụng ngOnInitcho logic khởi tạo không nhạy cảm theo thời gian, các lớp con có thể chọn có super.ngOnInit()được gọi hay không và khi nào:

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

Điều này sẽ không thể thực hiện với chỉ riêng nhà xây dựng.


12

Các câu trả lời trên không thực sự trả lời khía cạnh này của câu hỏi ban đầu: móc vòng đời là gì? Phải mất một thời gian tôi mới hiểu điều đó có nghĩa là gì cho đến khi tôi nghĩ về nó theo cách này.

1) Nói thành phần của bạn là một con người. Con người có cuộc sống bao gồm nhiều giai đoạn sống, và sau đó chúng ta hết hạn.

2) Thành phần con người của chúng ta có thể có kịch bản vòng đời sau: Sinh ra, Em bé, Lớp học, Người trưởng thành trẻ tuổi, Người trung niên, Người cao tuổi, Người chết, Bị vứt bỏ.

3) Nói rằng bạn muốn có một chức năng để tạo ra trẻ em. Để giữ cho điều này không trở nên phức tạp và khá hài hước, bạn muốn chức năng của mình chỉ được gọi trong giai đoạn Người trưởng thành trẻ của cuộc sống thành phần con người. Vì vậy, bạn phát triển một thành phần chỉ hoạt động khi thành phần cha mẹ ở giai đoạn Người trưởng thành trẻ tuổi. Móc giúp bạn làm điều đó bằng cách báo hiệu giai đoạn của cuộc sống và để cho thành phần của bạn hành động trên nó.

Công cụ thú vị. Nếu bạn để trí tưởng tượng của mình thực sự mã hóa thứ gì đó như thế này thì nó sẽ trở nên phức tạp và buồn cười.


7

Hàm tạo là một phương thức trong JavaScript và được coi là một tính năng của lớp trong es6. Khi lớp được khởi tạo, nó ngay lập tức chạy hàm tạo cho dù nó có được sử dụng trong khung Angular hay không. Vì vậy, nó được gọi bởi công cụ JavaScript và Angular không có kiểm soát điều đó

import {Component} from '@angular/core';
@Component({})
class CONSTRUCTORTEST {

//This is called by Javascript not the Angular.
     constructor(){
        console.log("view constructor initialised");
     }
}

Lớp "Con constructorTest" được khởi tạo bên dưới; Vì vậy, bên trong nó gọi hàm tạo (Tất cả những điều này xảy ra bởi JavaScript (es6) no Angular).

new CONSTRUCTORTEST();

Đó là lý do tại sao có ngOnInit vòng đời móc trong Angular.ngOnInit renders khi góc đã hoàn tất initialising các thành phần.

import {Component} from '@angular/core';
@Component({})
class NGONINITTEST implements onInit{
   constructor(){}
   //ngOnInit calls by Angular
   ngOnInit(){
     console.log("Testing ngOnInit");
   }
}

Đầu tiên chúng ta khởi tạo lớp như bên dưới, điều này xảy ra ngay lập tức khi chạy phương thức constructor.

let instance = new NGONINITTEST();

ngOnInit được gọi bởi Angular khi cần thiết như dưới đây:

instance.ngOnInit();

Nhưng bạn có thể hỏi tại sao chúng ta sử dụng constructor trong Angular?

Câu trả lời là tiêm phụ thuộc . Vì nó đã được đề cập trước đó, hàm tạo được gọi bởi công cụ JavaScript ngay lập tức khi lớp được khởi tạo (trước khi gọi ngOnInit bởi Angular), do đó, typcript giúp chúng ta có được loại phụ thuộc được xác định trong hàm tạo và cuối cùng cho biết Angular loại phụ thuộc mà chúng ta muốn sử dụng trong thành phần cụ thể đó.


7

Hai điều cần quan sát ở đây:

  1. Trình xây dựng được gọi bất cứ khi nào một đối tượng được tạo ra của lớp đó.
  2. ngOnInit được gọi khi thành phần được tạo.

Cả hai đều có khả năng sử dụng khác nhau.


5

constructor () là phương thức mặc định trong vòng đời Thành phần và được sử dụng để tiêm phụ thuộc. Trình xây dựng là một tính năng bản in.

ngOnInit () được gọi sau hàm tạo và ngOnInit được gọi sau ngOnChanges đầu tiên.

I E:

Trình xây dựng () -->ngOnChanges () -->ngOnInit ()

như đã đề cập ở trên ngOnChanges()được gọi khi giá trị ràng buộc đầu vào hoặc đầu ra thay đổi.


4

Cả hai phương pháp đều có mục tiêu / trách nhiệm khác nhau. Nhiệm vụ của hàm tạo (là một tính năng được hỗ trợ bằng ngôn ngữ) là đảm bảo rằng bất biến đại diện giữ. Mặt khác được nêu để đảm bảo rằng cá thể hợp lệ bằng cách đưa ra các giá trị chính xác cho các thành viên. Nhà phát triển phải quyết định 'chính xác' nghĩa là gì.

Nhiệm vụ của phương thức onInit () (là một khái niệm góc) là cho phép các yêu cầu phương thức trên một đối tượng chính xác (biểu diễn bất biến). Mỗi phương thức nên lần lượt đảm bảo rằng bất biến đại diện giữ khi phương thức kết thúc.

Hàm tạo nên được sử dụng để tạo các đối tượng 'chính xác', phương thức onInit cung cấp cho bạn cơ hội để gọi các cuộc gọi phương thức trong một trường hợp được xác định rõ.


4

Trình xây dựng: Phương thức hàm tạo trên lớp ES6 (hoặc TypeScript trong trường hợp này) là một tính năng của chính lớp đó, chứ không phải là một tính năng Angular. Nó nằm ngoài tầm kiểm soát của Angular khi hàm tạo được gọi, điều đó có nghĩa là nó không phải là một hook phù hợp để cho bạn biết khi nào Angular hoàn thành việc khởi tạo thành phần. Công cụ JavaScript gọi hàm tạo, không phải Angular trực tiếp. Đó là lý do tại sao móc vòng đời ngOnInit (và $ onInit trong AngularJS) được tạo ra. Ghi nhớ điều này, có một kịch bản phù hợp để sử dụng hàm tạo. Đây là khi chúng tôi muốn sử dụng phép nội xạ phụ thuộc - về cơ bản cho việc kết nối các phần phụ thuộc vào các thành phần.

Vì hàm tạo được khởi tạo bởi công cụ JavaScript và TypeScript cho phép chúng ta nói với Angular những phụ thuộc mà chúng ta yêu cầu để được ánh xạ với một thuộc tính cụ thể.

ngOnInit hoàn toàn ở đó để cho chúng ta một tín hiệu rằng Angular đã hoàn thành việc khởi tạo thành phần.

Giai đoạn này bao gồm đường chuyền đầu tiên tại Phát hiện thay đổi đối với các thuộc tính mà chúng ta có thể liên kết với chính thành phần đó - chẳng hạn như sử dụng trình trang trí @Input ().

Do đó, các thuộc tính @Input () có sẵn bên trong ngOnInit, tuy nhiên không được xác định bên trong hàm tạo, theo thiết kế


2

Trình xây dựng là lần đầu tiên và đôi khi nó xảy ra khi dữ liệu @input là null! vì vậy chúng tôi sử dụng Trình xây dựng để khai báo các dịch vụ và ngOnInit xảy ra sau đó. Ví dụ cho contrutor:

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

Ví dụ cho onInit:

ngOnInit() {
    this.items = [
      { label: 'A', icon: 'fa fa-home', routerLink: ['/'] },
      { label: 'B', icon: 'fa fa-home', routerLink: ['/'] }]
}

Tôi nghĩ rằng onInit giống như InitialComponents () trong winForm.


1

Trong vòng đời Angular

1) Tham số hàm tạo góc phát hiện ('s) và lớp khởi tạo.

2) Vòng đời gọi tiếp theo

Móc vòng đời góc

ngOnChanges -> Gọi ràng buộc tham số chỉ thị.

ngOnInit -> Bắt đầu kết xuất góc ...

Gọi phương pháp khác với trạng thái của vòng đời góc.


1

constructorđược gọi khi Angular "instanciates / constructs" thành phần. Các ngOnInitphương pháp là một cái móc mà đại diện cho phần khởi tạo của vòng đời phần. Một thực hành tốt là chỉ sử dụng nó để tiêm dịch vụ :

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

Ngay cả khi có thể, bạn cũng không nên thực hiện một số "công việc" bên trong. Nếu bạn muốn khởi chạy một số hành động phải xảy ra ở phần "khởi tạo" thành phần, hãy sử dụng ngOnInit:

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

Hơn nữa, các hành động liên quan đến các thuộc tính đầu vào , đến từ thành phần cha mẹ, không thể được thực hiện trong bộ điều khiển. Chúng nên được đặt trong ngOnInitphương thức hoặc một cái móc khác. Tương tự đối với phần tử liên quan đến chế độ xem (DOM), ví dụ, các phần tử khung nhìn :

@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
};

0

constructor() được sử dụng để làm tiêm phụ thuộc.

ngOnInit(), ngOnChanges()ngOnDestroy()vv là phương pháp vòng đời. ngOnChanges()sẽ là người đầu tiên được gọi, trước đó ngOnInit(), khi giá trị của một thuộc tính ràng buộc thay đổi, nó sẽ KHÔNG được gọi nếu không có thay đổi. ngOnDestroy()được gọi khi thành phần bị loại bỏ. Để sử dụng nó, OnDestroycần phải được implemented bởi lớp.


1
đồng ý, điều này là ngắn và rõ ràng. Ví dụ, constructor () là để thêm các đối tượng dịch vụ, ngOnInit () là để thao tác các thành phần với các lệnh gọi hàm dịch vụ cần thiết.
Steve

0

Tôi đã tìm thấy câu trả lời và tôi đã cố dịch nó sang tiếng Anh: Câu hỏi này vẫn phát sinh, ngay cả trong các cuộc phỏng vấn kỹ thuật. Trong thực tế, có một sự tương đồng lớn giữa hai người, nhưng cũng có một số khác biệt.

  • Hàm tạo là một phần của ECMAScript. Mặt khác ngOnInit () là một khái niệm về góc.

  • Chúng ta có thể gọi các hàm tạo trong tất cả các lớp ngay cả khi chúng ta không sử dụng Angular

  • Vòng đời: Hàm tạo được gọi trước ngOnInt ()

  • Trong hàm tạo, chúng ta không thể gọi các phần tử HTML. Tuy nhiên, trong ngOnInit () chúng ta có thể.

  • Nói chung, các cuộc gọi của dịch vụ trong ngOnInit () chứ không phải trong hàm tạo

    Nguồn: http://www.angular-tuto.com/Angular/Component#Diff


0

Constructor

Hàm constructor đi kèm với mọi lớp, các constructor không đặc trưng cho Angular nhưng là các khái niệm xuất phát từ các thiết kế hướng đối tượng. Hàm tạo tạo một thể hiện của lớp thành phần.

OnInit

Các ngOnInitchức năng là một trong những phương pháp vòng đời một thành phần góc của. Các phương thức vòng đời (hoặc móc) trong các thành phần Angular cho phép bạn chạy một đoạn mã ở các giai đoạn khác nhau trong vòng đời của một thành phần. Không giống như phương thức constructor, ngOnInitphương thức xuất phát từ giao diện Angular ( OnInit) mà thành phần cần triển khai để sử dụng phương thức này. Các ngOnInitphương pháp được gọi là một thời gian ngắn sau khi thành phần được tạo ra.


0

Trình xây dựng được thực thi khi lớp được khởi tạo. Nó không có gì để làm với các góc. Đây là tính năng của Javascript và Angular không có quyền kiểm soát nó

NgOnInit là đặc trưng của Angular và được gọi khi Angular đã khởi tạo thành phần với tất cả các thuộc tính đầu vào của nó

Các thuộc tính @Input có sẵn trong móc vòng đời ngOnInit. Điều này sẽ giúp bạn thực hiện một số công cụ khởi tạo như lấy dữ liệu từ máy chủ phụ, v.v. để hiển thị trong chế độ xem

Các thuộc tính @Input được hiển thị là không xác định bên trong hàm tạo


-1

Hàm xây dựng là một hàm được thực thi khi thành phần (hoặc lớp khác) được xây dựng.

ngOnInit là một hàm thuộc các nhóm phương thức vòng đời thành phần và chúng được thực thi trong một thời điểm khác nhau của thành phần của chúng tôi (đó là lý do tại sao đặt tên cho vòng đời). Dưới đây là danh sách tất cả chúng:

nhập mô tả hình ảnh ở đây Trình xây dựng sẽ được thực thi trước bất kỳ chức năng vòng đời nào.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.