angular 中的 forwardRef 是做什么的?
what does do forwardRef in angular?
forwardRef在angular中有什么作用,它的用法是什么?
这是一个 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!' }
来自 Angular's API docs on forwardRef
:
Allows to refer to references which are not yet defined.
For instance, forwardRef
is used when the token which we need to refer to for the
purposes of DI is declared, but not yet defined. It is also used when
the token which we use when creating a query is not yet defined.
摘录如下:
Why does forwardRef work?
Now the question may pop up in your head how the forwardRef
works. It actually has to do with how closures in JavaScript work. When you capture a variable inside a closure function it captures the variable reference, not the variable value. Here is the small example to demonstrate that:
let a;
function enclose() {
console.log(a);
}
enclose(); // undefined
a = 5;
enclose(); // 5
You can see that although the variable a
was undefined at the moment the enclose
function was created, it captured the variable reference. So when later the variable was updated to the 5
it logged the correct value.
And forwardRef
is just a function that captures a class reference into closure and class becomes defined before the function is executed. Angular compiler uses the function resolveForwardRef to unwrap the token or provider type during runtime.
根据 Angular 的文档:
Allows to refer to references which are not yet defined.
我认为,为了更好地理解 forwardRef 的工作原理,我们需要了解在 Java 脚本的幕后是如何发生的。我将提供您可能需要使用 forwardRef 的特定情况的示例,但要考虑到可能会出现其他不同情况。
正如我们所知,Java脚本函数被提升到其执行上下文的顶部。函数本身就是对象,其他对象也可以从函数创建。因为函数允许程序员创建对象实例,ECMAScript 2015 创建了某种语法糖以使 Javascript 感觉更接近基于 class 的语言,例如 Java。输入 class:
class SomeClassName { }
如果我们进入 Java 脚本编译器(在我的例子中我使用的是 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);
};
最有趣的部分是注意到我们的 class 实际上是一个后台函数。与函数一样,变量也在其执行上下文中被提升。唯一的区别是,虽然我们可以调用函数(因为我们可以引用它的指针,即使它被提升了),变量也会被提升并赋予默认值 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。这个函数的作用是它接受一个函数作为参数(在我展示的例子中我使用了箭头函数)。这个函数returns一个class。 forwardRef 等到 Service2Service 被声明,然后它触发被传递的箭头函数。这导致返回我们创建 Service2Service 实例所需的 class。因此,您的 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 允许我们引用稍后在我们的源代码中定义的类型,防止我们的代码崩溃并为我们在代码中组织事物的方式提供更大的灵活性.
真心希望我的回答对您有所帮助。 :)
forwardRef在angular中有什么作用,它的用法是什么?
这是一个 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!' }
来自 Angular's API docs on forwardRef
:
Allows to refer to references which are not yet defined.
For instance,
forwardRef
is used when the token which we need to refer to for the purposes of DI is declared, but not yet defined. It is also used when the token which we use when creating a query is not yet defined.
摘录如下:
Why does forwardRef work?
Now the question may pop up in your head how the
forwardRef
works. It actually has to do with how closures in JavaScript work. When you capture a variable inside a closure function it captures the variable reference, not the variable value. Here is the small example to demonstrate that:let a; function enclose() { console.log(a); } enclose(); // undefined a = 5; enclose(); // 5
You can see that although the variable
a
was undefined at the moment theenclose
function was created, it captured the variable reference. So when later the variable was updated to the5
it logged the correct value.And
forwardRef
is just a function that captures a class reference into closure and class becomes defined before the function is executed. Angular compiler uses the function resolveForwardRef to unwrap the token or provider type during runtime.
根据 Angular 的文档:
Allows to refer to references which are not yet defined.
我认为,为了更好地理解 forwardRef 的工作原理,我们需要了解在 Java 脚本的幕后是如何发生的。我将提供您可能需要使用 forwardRef 的特定情况的示例,但要考虑到可能会出现其他不同情况。
正如我们所知,Java脚本函数被提升到其执行上下文的顶部。函数本身就是对象,其他对象也可以从函数创建。因为函数允许程序员创建对象实例,ECMAScript 2015 创建了某种语法糖以使 Javascript 感觉更接近基于 class 的语言,例如 Java。输入 class:
class SomeClassName { }
如果我们进入 Java 脚本编译器(在我的例子中我使用的是 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);
};
最有趣的部分是注意到我们的 class 实际上是一个后台函数。与函数一样,变量也在其执行上下文中被提升。唯一的区别是,虽然我们可以调用函数(因为我们可以引用它的指针,即使它被提升了),变量也会被提升并赋予默认值 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。这个函数的作用是它接受一个函数作为参数(在我展示的例子中我使用了箭头函数)。这个函数returns一个class。 forwardRef 等到 Service2Service 被声明,然后它触发被传递的箭头函数。这导致返回我们创建 Service2Service 实例所需的 class。因此,您的 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 允许我们引用稍后在我们的源代码中定义的类型,防止我们的代码崩溃并为我们在代码中组织事物的方式提供更大的灵活性.
真心希望我的回答对您有所帮助。 :)