我在理解 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
。这是"另一个"this
onClick={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
,如果未指定,则将this
undefined
资料来源: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 元素通常会连同它们的事件侦听器一起进行垃圾回收,但如果内存中仍有对该元素的引用,则不会对其进行垃圾回收。