代码之家  ›  专栏  ›  技术社区  ›  unos baghaii

forwardref在角度上做什么?

  •  5
  • unos baghaii  · 技术社区  · 6 年前

    什么? 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 回复  |  直到 6 年前
        1
  •  5
  •   ruffin    6 年前

    Angular's API docs on forwardRef :

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

    例如, 前馈 当我们需要引用的令牌 DI的目的已声明,但尚未定义。当 创建查询时使用的标记尚未定义。

    有一篇很好的报道 Angular In Depth .

    以下是摘录:

    为什么forwardref工作?

    现在问题可能会在你脑海中浮现 前馈 作品。它实际上与javascript中的闭包如何工作有关。当您在闭包函数中捕获变量时,它将捕获 变量引用 而不是 可变值 . 下面是一个小例子来说明:

    let a;
    function enclose() {
        console.log(a);
    }
    
    enclose(); // undefined
    
    a = 5;
    enclose(); // 5
    

    你可以看到,尽管变量 a 当时还没有定义 enclose 函数被创建,它捕获了变量引用。所以后来变量被更新为 5 它记录了正确的值。

    前馈 只是一个函数,它将类引用捕获到闭包中,然后在执行该函数之前定义类。角度编译器使用函数 resolveForwardRef 在运行时打开令牌或提供程序类型。

        2
  •  8
  •   Armando Perez    6 年前

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

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

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

    实际上变成:

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

    好吧,考虑到所有这些,我们现在就进入角度。假设我们的应用程序中有以下代码:

    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

    嗯,有意思…怎么回事?根据之前的解释, 服务2服务 在后台成为一个函数,但是这个函数被分配到一个变量中。此变量已被提升,但其值未定义。因此,无法解析参数。

    输入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允许我们引用稍后在源代码中定义的类型,防止代码崩溃,并在代码中组织内容的方式上提供更大的灵活性。

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

    推荐文章