什么做forwardRef角度?

时间:2018-06-17 07:24:09

标签: angular forward-reference

forwardRef在角度方面做了什么,它的用途是什么?

这是一个example

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

export class ClassCL { value; }

@Component({
    selector: 'my-app',
    template: '<h1>{{ text }}</h1>',
    providers: [{provide: ClassCL, useClass: forwardRef(() => ForwardRefS)}]
})
export class AppComponent {
    text;

    constructor( myClass: ClassCL ) {
        this.text = myClass.value;
    }
}

Injectable()
export class ForwardRefS { value = 'forwardRef works!' }

2 个答案:

答案 0 :(得分:7)

根据Angular的文档:

  

允许引用尚未定义的引用。

我相信,为了更好地了解forwardRef的工作原理,我们需要了解Javascript的内容是如何发生的。我将提供一个特定情况的示例,您可能需要使用forwardRef,但考虑到可能出现其他不同情况。

我们可能知道,Javascript函数被提升到其执行上下文的顶部。函数本身就是对象,也可以从函数中创建其他对象。因为函数允许程序员创建对象实例,所以ECMAScript 2015创建了一些语法糖,以使Javascript更接近基于类的语言,如Java。输入课程:

class SomeClassName { }

如果我们进入Javascript编译器(在我的情况下我使用的是Babel)并粘贴它,结果将是:

"use strict";

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var SomeClassName = function SomeClassName() {
  _classCallCheck(this, SomeClassName);
};

最有趣的部分是注意到我们班级在现实中是后台的一个功能。与函数一样,变量也在其执行上下文中提升。唯一的区别是,虽然我们可以调用函数(因为我们可以引用它的指针,即使它被提升),但是变量被提升并且给定默认值undefined。在赋值的给定行的运行时,为变量分配一个值,可能不是undefined。例如:

console.log(name);
var name = 'John Snow';

实际上变成:

var name = undefined;
console.log(name) // which prints undefined
name = 'John Snow';

好的,考虑到这一切,让我们现在跳进Angular。我们假设我们的应用程序中包含以下代码:

import { Component, Inject, forwardRef, Injectable } from '@angular/core';

@Injectable()
export class Service1Service {
    constructor(private service2Service: Service2Service) {
    }

    getSomeStringValue(): string {
        return this.service2Service.getSomeStringValue();
    }
}

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    constructor(private service1Service: Service1Service) {
        console.log(this.service1Service.getSomeStringValue());
    }
}

export class Service2Service {
    getSomeStringValue(): string {
        return 'Some string value.';
    }
}

当然,我们需要提供这些服务。让我们在AppModule中提供它们:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';


import { AppComponent, Service1Service, Service2Service } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [Service1Service, Service2Service],
  bootstrap: [AppComponent]
})
export class AppModule { }

AppModule元数据中的重要一行是:

providers: [Service1Service, Service2Service]

如果我们运行此代码,我们会收到以下错误:

enter image description here

嗯,有趣......这里发生了什么?那么,根据前面给出的解释, Service2Service 在后台成为一个函数,但是这个函数被赋值给一个变量。此变量已提升,但其值未定义。由于这一切,无法解析参数。

输入forwardRef

为了解决这个问题,我们有一个名为 forwardRef 的漂亮功能。这个函数的作用是它将一个函数作为一个参数(在我展示的例子中我使用了一个箭头函数)。该函数返回一个类。 forwardRef等待,直到声明Service2Service,然后它触发传递的箭头函数。这导致返回我们需要的类以创建Service2Service实例。所以,你的app.component.ts代码看起来像这样:

import { Component, Inject, forwardRef, Injectable } from '@angular/core';

@Injectable()
export class Service1Service {
    constructor(@Inject(forwardRef(() => Service2Service)) private service2Service) {
    }

    getSomeStringValue(): string {
        return this.service2Service.getSomeStringValue();
    }
}

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    constructor(private service1Service: Service1Service) {
        console.log(this.service1Service.getSomeStringValue());
    }
}

export class Service2Service {
    getSomeStringValue(): string {
        return 'Some string value.';
    }
}

总之,根据我提供的示例,forwardRef允许我们引用稍后在源代码中定义的类型,从而防止我们的代码崩溃,并为我们在代码中组织事物提供更多灵活性。 / p>

我真的希望我的答案对你有好处。 :)

答案 1 :(得分:3)

来自Angular's API docs on forwardRef

  

允许引用尚未定义的引用。

     

例如,当我们需要引用的令牌时使用forwardRef   DI的目的是宣布,但尚未定义。它也用于   我们在创建查询时使用的令牌尚未定义。

有一个很好的写作 Angular In Depth

这是一个摘录:

  

为什么forwardRef有效?

     

现在问题可能会突然出现forwardRef的工作原理。它实际上与JavaScript中的闭包工作方式有关。在闭包函数中捕获变量时,它会捕获变量引用,而不是变量值。以下是证明:

的小例子
let a;
function enclose() {
    console.log(a);
}

enclose(); // undefined

a = 5;
enclose(); // 5
     

您可以看到,虽然变量a在创建enclose函数时未定义,但它捕获了变量引用。因此,当稍后变量更新为5时,它会记录正确的值。

     

forwardRef只是一个函数,它将类引用捕获到闭包中,并且在执行函数之前定义了类。 Angular编译器使用函数resolveForwardRef在运行时解包令牌或提供者类型。