Binding in React:如果我不绑定,"这"指的是什么?



我在理解 React(或一般的 JS)中的整个this问题时遇到了一些问题,并发现了这篇非常有用的文章:

https://medium.freecodecamp.org/react-binding-patterns-5-approaches-for-handling-this-92c651b5af56

但是,有一件基本的事情我仍然不确定。

让我们以方法 2 为例:

// Approach 2: Bind in Render
class HelloWorld extends React.Component {
constructor(props) {
super(props);
this.state = { message: 'Hi' };
}
logMessage() {
// This works because of the bind in render below.
console.log(this.state.message);
}
render() {
return (
<input type="button" value="Log" onClick={this.logMessage.bind(this)} />
);
}
}

现在,让我们看看这段代码的错误版本,我们只是没有执行引用正确this(HelloWorld 组件)所需的绑定:

// Wrong "naive" version of the code
class HelloWorld extends React.Component {
constructor(props) {
super(props);
this.state = { message: 'Hi' };
}
logMessage() {
// This works because of the bind in render below.
console.log(this.state.message);
}
render() {
return (
<input type="button" value="Log" onClick={this.logMessage} />
);
}
}

我的问题很简单:在那个错误的版本中,我的理解是 logMessage 函数中console.log(this.state.message)中的this不再引用 HelloWorld 类对象。它指的是什么?谢谢!

编辑:事实证明我的理解是错误的。这不是不再起作用的this。这是"另一个"thisonClick={this.logMessage}!原因将在下面的答案中给出 - 只是想在问题中纠正这一点。

每当使用 -()调用函数时,函数上下文 -this都会根据()之前的任何内容自动设置。

例如

let A = {
foo() {
console.log(this === A);
}
};

当你这样称呼foo——

A.foo() // prints true

foo接收的上下文函数取决于A.foo,这里A。但是当您使用不同的成员调用 SAME 函数时 - 例如 -

let B = {
foo: A.foo
};
B.foo(); // prints false

即使您仍在调用完全相同的函数,函数/方法foo接收不同的上下文(此处B) -

有时,您可以使用以下三件事之一强制函数的上下文 -

1..bind

文档: MDN

bind() 方法创建一个新函数,该函数在调用时将其 this 关键字设置为提供的值,并在调用新函数时提供的任何参数序列之前具有给定的参数序列。

阿拉伯数字。.call.apply

它们都使用给定的this值调用函数。

文档: MDN Function.prototype.call

文档: MDN Function.prototype.apply

3.箭头功能

文档:MDN 箭头函数

.class

JavaScript 类方法具有相同的概念 -

class A {
foo() {
console.log(this instanceof A);
}
}
let a = new A();
a.foo(); // prints true

当您运行将此函数分配给不同对象的不同方法的实验时,

let b = {
foo: a.foo
};
b.foo(); // prints false

每当您将函数传递到其他地方时,您不会随它一起传递上下文,而是通过使用this

问题的根源

在您的示例中,

<input type="button" value="Log" onClick={this.logMessage} />

具体说来

onClick={this.logMessage}

这类似于上面的例子——

let b = {
foo: a.foo
};

所以,现在,无论谁使用b.foo(这里是 React)调用你的函数,都需要知道上下文。因此,在将函数传递给onClick之前,您必须为函数设置上下文

如果你不绑定,它指的是什么?

strict mode,会发生以下情况——

因此,对于严格模式函数,指定的this不会被框object,如果未指定,则将thisundefined

资料来源:MDN第"Securing JavaScript"

在上述所有带有b.foo的示例中,如果将其分配给变量而不是对象属性,

let c = a.foo;
c(); // this will be undefined in foo

因此,在您的logMessage方法中,this的值将undefined

这总是指类的属性和行为,但你必须将其绑定到要在其中使用这些属性和行为的函数。如果您没有将类级别与函数绑定,则该函数中的"this"仅指该函数上下文中的属性。

你也可以在组件周期的回调中绑定它,比如componentWillMount,构造函数或任何引用类的地方。

福考普:

componentWillMount(){
this.anyCallBack = this.anyCallBack.bind(this);
}
anycallBack(){
//now this will refer to the class
console.log(this);
}

"this"的默认值取决于要绑定到的事件。 对于JavaScript,一般来说,DOM事件,如onClick或onChange,将"this"作为指向触发事件的DOM元素的指针。 例如,如果您要创建一个按钮并附加一个单击侦听器,并在该侦听器中使用 console.log(this),您将看到该按钮是 this 的值。

注意:默认情况下,React 将"this"设置为未定义。

setTimeout 和 setInterval 的事件处理程序会将"this"设置为指向窗口对象的指针。

使用绑定存在继承危险。 每次绑定到方法时,JavaScript 都会创建一个新方法。 新方法是匿名方法,除非您将其值设置为属性或变量:

let myBoundMethod = myMethod.bind(this);

如果需要将事件与 DOM 元素分离,除非您具有对绑定方法的引用,否则您将无法从事件中删除事件侦听器。 这可能是应用程序中内存泄漏的来源。 始终使用调试工具来监视内存使用情况。 它上升和下降是正常的,但它应该有一个相对稳定的基线。

从 DOM 中删除的 DOM 元素通常会连同它们的事件侦听器一起进行垃圾回收,但如果内存中仍有对该元素的引用,则不会对其进行垃圾回收。

最新更新