首页 > 解决方案 > forwardRef 在角度上有什么作用?

问题描述

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

这是一个例子

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

标签: angularforward-reference

解决方案


根据 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。变量在运行时在赋值的给定行被分配了一个值,可能不是未定义的。例如:

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]

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

在此处输入图像描述

嗯,有趣……这是怎么回事?嗯,根据前面的解释,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 允许我们引用稍后在源代码中定义的类型,从而防止我们的代码崩溃并为我们在代码中组织事物的方式提供更大的灵活性。

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


推荐阅读