首页 > 解决方案 > 为什么其中一个管道正确引用了“this”而另一个没有?

问题描述

我正在构建一个可管道化的运算符,但发现自己对这两种方法排列之间的区别究竟是什么视而不见。一个有效,另一个无效。

export class CrudService {

  constructor(private datastore: DatastoreService,
              private http: HttpClient) { }

  // Making the operator an attribute on the object 
  // instance allows `this.datastore` to work as expected ✅

  upsertResponse = (source: any) =>
    source.pipe(
      map((data: any) => {
        this.datastore.validate_and_upsert(data)
        return true
      })
    )
}
export class CrudService {

  constructor(private datastore: DatastoreService,
              private http: HttpClient) { }

  // Making the operator an instance method means that 
  // `this.datastore` throws an error ❌

  upsertResponse(source: any){
    return source.pipe(
      map((data: any) => {
        this.datastore.validate_and_upsert(data)
        return true
      })
    )
  }
}

为什么this.datastore.validate_and_upsert一个有效,另一个无效?

根据版主建议编辑

这个问题已被改写,以使其更密切地关注导致问题的原因。

标签: angulartypescriptrxjs

解决方案


它们都是可管道的,但只有一个可以访问this类的上下文。我想你可以猜到是哪一个。作为属性制作的那个。有一种方法可以使用.bind(this)

readonly obs$ = this.http.get().pipe(
  this.upsertResponse.bind(this)
);

upsertResponse<T>(source: Observable<T>){
  return source.pipe(
    tap((data) => this.datastore.validate_and_upsert(data)),
    mapTo(true)
  );
}

或者仅使用整个可观察对象作为源,但它不再是管道:

readonly obs$ = this.upsertResponse(this.http.get());

但明智的意见,我相信你问题中的属性方式更好。

readonly upsertResponse = //...;

这样您就不必担心 this 上下文,而且很明显该方法是一个实用方法。

仅供参考,当您添加事件侦听器时会发生同样的事情,您可以通过使用匿名箭头函数来解决它,这不是可管道运算符的选项:
document.addEventListener('click', (event) => this.upsertEvent(event)); 

更深入的测试类:

如果你有这个课程:

class TestClass {
  readonly attributeMethod = () => {
    this.executeThis()
  };

  functionMethod() {
    this.executeThis();
  }

  executeThis() {
    console.log('hi');
  }

  constructor() {
    document.addEventListener('click', this.functionMethod);
    document.addEventListener('click', this.attributeMethod);
  }
}

这将以角度转换为 ES5(不幸的是),这将导致:

"use strict";
var TestClass = /** @class */ (function () {
    function TestClass() {
        var _this = this;
        this.attributeMethod = function () {
            _this.executeThis();
        };
        document.addEventListener('click', this.functionMethod);
        document.addEventListener('click', this.attributeMethod);
    }
    TestClass.prototype.functionMethod = function () {
        this.executeThis();
    };
    TestClass.prototype.executeThis = function () {
        console.log('hi');
    };
    return TestClass;
}());

看这里

如您所见,functionMethodgets 放置在构造函数中,prototype并且attributeMethodis 位于TestClass构造函数中。但是,只有可以通过使用attributeMethod来访问this类的_this = this

因此,当您将functionMethod引用作为回调方法传递时,该方法将在实际执行该方法的上下文中调用。对 的引用也会发生同样的事情attributeMethod,不同之处在于attributeMethod_this = this其范围内。


推荐阅读