我发现有些困惑,有时您需要将上下文绑定到函数调用,有时则不需要。究竟什么时候可以避免,什么时候可以避免?
这些行之间有什么区别?
<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)
使函数调用起作用,有时却不起作用。所有这些案例之间有什么区别?
答案 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}!`);
}
}
但名称未显示在警报中:
如果我们查看两个函数中的 this
,我们会得到不同的结果:
一个是 HTMLElement,另一个是 Window。一旦我们将 this
传递给 sayHi
,setTimeout
所指的是不同的。
Bind
将通过确保 this 指向正确的对象来解决此问题。
虽然我们可以执行 setTimeout(this.sayHi.bind(this), 1000);
并且它会解决我们的问题,但它不是很干净并且容易出错。我们可以在构造函数中绑定它,但这也好不到哪里去。
最简洁的方法是使用箭头函数直接绑定 this
:
sayHi = () => {
[...]
此表示法将 this
绑定到对象本身。然后我们不需要自己明确绑定它。
一旦我们这样做了,this
都指向正确的对象: