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!' }
答案 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]
如果我们运行此代码,我们会收到以下错误:
嗯,有趣......这里发生了什么?那么,根据前面给出的解释, 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在运行时解包令牌或提供者类型。