为什么其中一个管道正确地引用了“ this”,而另一个却没有呢?

时间:2020-09-30 07:58:53

标签: angular typescript rxjs

我正在构建一个可操作的运算符,但发现自己对方法的这两种排列之间的确切区别一无所知。一种有效,另一种无效。

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在一个而不是另一个中起作用?

根据主持人的建议进行编辑

该问题已被重新表述,以使其更加关注导致问题的原因。

1 个答案:

答案 0 :(得分:3)

它们都是可管道的,但是只有一个可以访问该类的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 = //...;

这样,您不必担心此上下文,很明显,该方法是实用程序方法。

费耶,添加事件侦听器时也会发生同样的事情,在那里您可以使用匿名箭头函数来解决它,这不是可管道运算符的选项:
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;
}());

see here

您可以看到functionMethod被放置在prototype上,并且attributeMethodTestClass构造函数中。但是,只有attributeMethod可以通过使用this来访问类的_this = this

因此,当您将functionMethod引用作为回调方法传递时,无论实际执行该方法的内容如何,​​都会调用此方法。对attributeMethod的引用发生了相同的事情,不同之处在于attributeMethod的范围内有_this = this