在React中绑定:如果我不绑定,那么“this”是指什么?

时间:2018-03-11 12:50:54

标签: reactjs

我在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}!原因将在下面的答案中给出 - 只是想在这里纠正这个问题。

3 个答案:

答案 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) -

有时,您可以使用以下三种方法之一来强制执行函数的上下文 -

1。 .bind

Docs: MDN

  

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

2。 .call.apply

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

Docs: MDN Function.prototype.call

Docs: MDN Function.prototype.apply

3。箭头功能

Docs: MDN Arrow functions

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"

部分下的

Source: MDN

在所有上面的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元素通常会与其事件侦听器一起进行垃圾回收,但如果内存中仍有对该元素的引用,则不会对其进行垃圾回收。