我在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函数中的this
中的console.log(this.state.message)
不再引用HelloWorld类对象。相反,它指的是什么?谢谢!
this
不再起作用的。它是this
的“另一个”onClick={this.logMessage}
!原因将在下面的答案中给出 - 只是想在这里纠正这个问题。
答案 0 :(得分:3)
每当使用 - ()
调用函数时,函数上下文 - 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
) -
有时,您可以使用以下三种方法之一来强制执行函数的上下文 -
.bind
bind()方法创建一个新函数,在调用时,将其this关键字设置为提供的值,并在调用新函数时提供任何前面提供的给定参数序列。
.call
,.apply
他们都使用给定的this
值调用函数。
Docs: MDN Function.prototype.call
Docs: MDN Function.prototype.apply
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
"Securing JavaScript"
部分下的在所有上面的b.foo
示例中,如果将其分配给变量而不是对象属性,
let c = a.foo;
c(); // this will be undefined in foo
因此,在logMessage
方法中,this
的值为undefined
。
答案 1 :(得分:1)
这总是指您的类的属性和行为,但您必须将其绑定到您要使用这些属性和行为的函数。如果你没有将类级别与函数绑定,那么该函数中的“this”仅指该函数上下文中的属性。
您还可以在组件周期的回调中绑定它,例如componentWillMount,构造函数或其具有对类的引用的任何位置。
Forexampe:
componentWillMount(){
this.anyCallBack = this.anyCallBack.bind(this);
}
anycallBack(){
//now this will refer to the class
console.log(this);
}
答案 2 :(得分:1)
'this'的默认值取决于您绑定的事件。通常,使用JavaScript,DOM事件(例如onClick或onChange)将“this”作为指向触发事件的DOM元素的指针。例如,如果您要创建一个按钮并附加一个单击侦听器,并在该侦听器中使用console.log(this),您将看到该按钮是此值。
注意:默认情况下,React将'this'设置为undefined。
setTimeout和setInterval的事件处理程序将'this'设置为指向窗口对象的指针。
使用bind存在继承的危险。每次绑定到方法时,JavaScript都会创建一个新方法。除非将其值设置为属性或变量,否则新方法是匿名方法:
让myBoundMethod = myMethod.bind(this);
如果需要从DOM元素中分离事件,除非您引用了绑定方法,否则将无法从事件中删除事件侦听器。这可能是应用程序中内存泄漏的原因。始终使用调试工具来监视内存使用情况。上升和下降是正常的,但它应该具有相对稳定的基线。
从DOM中删除的DOM元素通常会与其事件侦听器一起进行垃圾回收,但如果内存中仍有对该元素的引用,则不会对其进行垃圾回收。