我是否误解了React甚至Javascript中对this的使用?

时间:2019-05-02 12:01:28

标签: javascript reactjs

关于此主题的问题已经有好几个了,我已经查看了所发现的所有内容-我的问题是为了为我自己消除一些正在出现的(明显的)矛盾。我怀疑有比我目前唯一的解决方案更好的解决方案。我是Java语言的新手。

我已经阅读了this上的范围规则,例如https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this。从阅读中我的理解是,尽管很大程度上取决于调用上下文,但是如果函数是对象的方法,则函数this中的对象将是对象本身。我以为这个规则胜过其他规则,但也许我误会了。

我还阅读了https://medium.com/byte-sized-react/what-is-this-in-react-25c62c31480上的一篇帖子,该帖子基本上说,如果我想通过this在方法中访问对象状态,并且我有类似

的代码
class App extends Component {
  constructor(props) {
    super(props);
  }
  clickFunction() {
    console.log(this.props.value);
  }
  render() {
    return(
      <div onClick={this.clickFunction}>Click Me!</div>
    );
  }
}

然后我需要通过向构造函数添加一行,例如

,将对象显式绑定到clickFunction()
this.clickFunction = this.clickFunction.bind(this);

或通过使用箭头符号来定义clickFunction(),例如

const clickFunction = () => { ... }

这些解决方案中的第一个对我有效-我还没有第二个解决方案。我似乎需要使用任何一种解决方案,这对我来说很奇怪,因为(a)似乎与我认为文档中的断言相反,即对象方法会将对象视为this,并且(b)我不赞成在我看到的其他教程示例中,看不到有人在做这种事情。

例如,在https://reactjs.org/tutorial/tutorial.html上有一个React教程,它定义了renderSquare(i)之类的对象方法,并且在任何时候都没有将这些方法显式绑定到对象。

如果我尝试做一些与我的教程完全相似的事情,并且没有在构造函数中显式添加行以将每个方法绑定到对象,例如this.clickFunction = this.clickFunction.bind(this)这样的行,那么我可以让我的代码正常工作。

任何人都可以向我解释我对教程和文档的误解-即使没有与对象的显式绑定,为什么该教程仍能正常工作?我可以发现它和自己的代码之间的唯一区别是我有use strict。是否有比我目前使用的this.clickFunction.bind(this)解决方案更好的解决方案?每个方法向构造函数添加一行额外的代码,以显式绑定我的所有方法,似乎很麻烦。

5 个答案:

答案 0 :(得分:3)

箭头函数将您的函数直接绑定到类。但是,如果您使用

const clickFunction = () => { ... }

这将创建一个内部函数,并且不会将其绑定到类。

您可以使用

clickFunction = () => { ... }

类似

this.clickFunction = this.clickFunction.bind(this);

答案 1 :(得分:1)

您是对的,当从对象调用函数时,this关键字最终成为该对象。所以运行类似的东西:

const app = new App();
app.clickFunction();

会产生您期望的结果,因为它是直接从App类中调用的。

但是,当您在JSX中将该函数用作事件处理程序时,您会将对该函数的引用作为回调传递。默认情况下,函数的this关键字直到您调用它时才确定,因此将根据调用它的词法上下文对其进行分配。您可以想象,在设置处理程序时,实际上发生了以下情况:

const callback = app.clickFunction;
// click event happens
callback(event);

在这里您可以看到对callback()的调用只是一个简单的函数调用。没有app.前缀为this提供词法上下文。

已经列出了两种解决此问题的方法,将this关键字显式设置为它们最初存在的对象。调用this.clickFunction = this.clickFunction.bind(this)是最明确的方法,因为它具有常规功能,并且在对象构造期间将this手动绑定到this的值。这将是正在构造的对象。

箭头函数执行相同的操作,但是没有显式绑定。实际上,这实际上是箭头功能和常规功能之间的功能差异,许多人通常会忽略它们,因为它们通常是出于样式或简洁的目的而选择的。可以说,箭头函数的行为像大多数程序员所期望的 ,而普通函数的行为是Java脚本特有的(因此相当混乱)。

答案 2 :(得分:0)

第二个箭头方法,它将在此方法定义的地方(而不是从调用它的地方)引用此参考。因此它将采用该类的参考。

参考this in arrow function

答案 3 :(得分:0)

您有有效的积分

为什么教程有效?如果看到renderSquare实现,您会注意到它在实现中未使用this,因此它不必与此绑定。您的实现可能无法正常运行,因为您可能在方法实现内部使用了this

renderSquare(i) {
  return <Square value={i} />;
}

当您获得诸如this.clickFunction之类的引用时,您只会得到未绑定到任何对象的特定函数的引用,这就是为什么如果尝试使用this来引用变量,则调用该函数将失败的原因

请参阅此小提琴https://jsfiddle.net/yh3jw5nk/1/以获取更多说明

答案 4 :(得分:0)

这是在运行时确定的,取决于代码,它可能有所不同。

这是

  • 在运行时由调用函数确定
  • 取决于函数的调用方式,而不是函数的位置 已定义
  • 对对象的引用。
  • 将始终是对象
  • 全局(此)在严格模式下不可用

示例1: this = window

var name = 'Global';

var callName1 = function() {
  var name = 'Peter';
  console.log('--- From callName1 ----');
  console.log(this.name);
  //console.log(this);
  callName2();
}


var callName2 = function() {
  var name = 'Jane';
  console.log('--- From callName2 ----');
  console.log(this.name);
  //console.log(this);
}

callName1();

var execute = function(fn) {
  var name = 'Mary';
  console.log('--- From execute ----');
  console.log(this.name);
  //console.log(this);
}

execute(callName2);

示例2:在严格模式下不可用

'use strict';

var name = 'Global';

var callName1 = function() {
  var name = 'Peter';
  console.log('--- From callName1 ----');
  console.log(this.name);
  console.log(this);
}

callName1();

示例3:使用方法调用检查 this

var name = 'global';

var obj = {
  name: 'James Obj1',
  func: function() {
    console.log('--- From func ----');
    console.log(this.name);
    console.log(this); // this reference obj1
  }
}

obj.func()

var obj2 = {
  name: 'Jame Obj2',
  func: obj.func // this reference obj2, but the function is defined in obj1
}

obj2.func()

var obj3 = {
  name: 'Kane Obj3',
  obj4: {
    name: 'Mary Obj4',
    func: function () {
      console.log('--- From obj4 ----');
      console.log(this.name);
      console.log(this); // this reference obj4
    }
  }
}
obj3.obj4.func()

使用() => {}函数 this -具有词法绑定。这意味着它使用包含箭头功能的代码中的this