LitElement和.bind(this)

时间:2019-10-20 12:11:30

标签: lit-element

我发现有些困惑,有时您需要将上下文绑定到函数调用,有时则不需要。究竟什么时候可以避免,什么时候可以避免?

这些行之间有什么区别?

<a @click="${this.handler.bind(this)}">link</a>

<a @click="${this.handler()}">link</a>

<a @click="${this.handler}">link</a>

<a @click="${()=>this.handler()}">link</a>

有时甚至需要在constructor()

this.handler = this.handler.bind(this)

使函数调用起作用,有时却不起作用。所有这些案例之间有什么区别?

2 个答案:

答案 0 :(得分:0)

在前四行中,我猜您通常将它们包装在${}之间。 提到这三行:

<a @click="${this.handler.bind(this)}">link</a>
<a @click="${this.handler}">link</a>
<a @click="${()=>this.handler()}">link</a>

效果会非常相似。附加事件处理程序时,您需要传递对要调用的函数/方法的引用,而第二行:

<a @click="${this.handler()}">link</a>

很可能只是错误的。这是因为渲染完成后,您将立即调用this.handler()。可能有意义的唯一方法是,如果handler方法返回一个函数。

回到前三行:它们的作用确实非常相似,因为在所有这三行中,您都将引用传递给本地方法render,但是:

  • 第一个不需要绑定,因为该方法仍然是 在this上下文中调用(但我想也不会受到伤害)
  • 第三个将匿名函数的定义添加为 事件处理程序,调用该处理程序时将调用this.handler

因此,第二个基本上是最简单,最容易阅读的。

在某些情况下需要调用绑定:从另一个上下文调用您的方法时需要。假设您将其作为回调参数传递给在另一个类中运行的方法。当您在此处调用方法时,默认情况下它将具有该另一个对象的上下文。因此,您将需要使用.bind(this)来确保在元素的上下文中调用该方法时。

您的方法确实有效,但是它是从另一个this开始运行的。因此,也许这就是为什么您有时没有注意到需要.bind(this)的原因。如果该方法仅显示消息,调用其他外部服务或不属于对象定义的任何其他内容(不使用this.something),则无需使用绑定即可工作。

更新:实际上,我认为事件处理程序将始终在引发该事件的元素的上下文中运行。我猜想,当我们使用.bind(this)语法时,lit只是@click=的原因,因为这很有意义。

答案 1 :(得分:0)

请注意,直接在模板中绑定通常不是一个好主意。它可能会导致性能问题和组件在不应该重新呈现时重新呈现。 https://github.com/43081j/eslint-plugin-lit/blob/master/docs/rules/no-template-bind.md

至于为什么有时需要绑定,请考虑:

@customElement('main-page')
export class MainPage extends LitElement {
  @property()
  public name = "bob";

  render() {
    return html`<button @click=${this.clicked}>Click Me!</button>`;
  }

  clicked() {
      console.log("clicked " + this.name);
      console.log("this in clicked: " + this)
      setTimeout(this.sayHi, 1000);
  }

  sayHi() {
    console.log("this in sayHi: " + this)
    alert(`Hello, ${this.name}!`);
  }
 }

如果我们点击按钮,我们会正确记录名称: enter image description here

但名称未显示在警报中:

enter image description here

如果我们查看两个函数中的 this,我们会得到不同的结果:

enter image description here

一个是 HTMLElement,另一个是 Window。一旦我们将 this 传递给 sayHisetTimeout 所指的是不同的。

Bind 将通过确保 this 指向正确的对象来解决此问题。

虽然我们可以执行 setTimeout(this.sayHi.bind(this), 1000); 并且它会解决我们的问题,但它不是很干净并且容易出错。我们可以在构造函数中绑定它,但这也好不到哪里去。

最简洁的方法是使用箭头函数直接绑定 this

sayHi = () => {
[...]

此表示法将 this 绑定到对象本身。然后我们不需要自己明确绑定它。 一旦我们这样做了,this 都指向正确的对象:

enter image description here