React中为什么要绑定事件

431 阅读3分钟

先看看下面的例子:

function foo() {
  console.log(this.name)
}
var man = {"name": "jack"}
foo() // undefined
// bind man to foo
foo = foo.bind(man) // 将foo中的name指向man中的name
foo() // jack

在将 man 绑定到 foo 之前,foo 是一个常规函数,没有引用 'name',因此,当你调用 this.name时,它不会打印任何内容。 但是,当我们将 man绑定到 foo 对象时,foo 现在有一个 'this' 引用(现在是'man'),它会从 man 对象中打印出 'name'。

function foo() {
  console.log(this.name)
}
var man = {"name": "jack"}
foo() // undefined
// Attach foo to man as a property
man.foo = foo
man.foo() // jack
// Copy man.foo to a new var bar
var bar = man.foo
bar() // undefined (WTF?)

当我们将 foo 附加到 man 并将在 man 上调用时,可以看到,foo 可以获取 man 的名字并正确地打印了 'jack'。 但当我们创建一个新的变量 bar 并将 man.foo 复制到 bar 时会发生什么? 我们看到突然间,man.foo 失去了 'this' 。 因为从 bar 中获取的 'this' 并不是 man,而是全局的 window 对象,在 window 下,我们没有定义 'name' 字段。 如何解决这个问题?没错, 我们可以使用 bind !

var man = {"name": "jack"};
var bar = foo.bind(man);
bar();

现在它生效了。但是它在类中会发生什么呢?请记住,JavaScript 中的类只是构造函数的语法糖,这意味着,类中的表现与这个完全相同。

但是,为什么我会将类方法复制到一个变量上使用?听起来很没有道理,但这正是我们在创建回调时发生的……

回调

应责怪 JavaScript,而不是 React

所以通常我们会在构造函数里bind事件,目的是将原型方法中的this指向新生成的实例,因为ES6中的class是不能自动分配this指向的,JSX实际是React.createElement()的语法糖:

render(){
	return (
		<a onClick={this.handleClick}>click me</a>
	)
}

//等价于

render(){
	return(
		React.createElement( // JSX
			"a",
			{onClick: this.handleClick}, // 此时如果没有bind,this为undefined
			"click me"
		)
	)
}

我们看React.createElement的第二个参数,传入的是一个对象,而这个对象里面有属性的值是取this 对象里面的属性 ,当这个对象放入React.createElement执行后,去取这个this.handleClick属性时候,this已经不是我们在书写的时候认为的绑定在View上了。

  • this实际上是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用,类中某一个属性值(方法),方法中的this需要看方法执行的时候,前面是否有".",才能知道this是谁

在React中,this是指向当前组件的一个实例,当方法执行的时候,方法内中的this就是执行方法时,这个方法“."前面的那个this,而上面说到,JSX实际是React.createElement()的语法糖,方法是通过对象传入的,这个对象里面的this在组件每次的生命周期中会丢失其**执行上下文环境,**导致this为undefined,而我们又是通过“回调”的方式——将函数赋值给一个变量,这样同样会导致函数丢失其执行上下文环境,为避免这种情况才使用bind明确绑定函数执行上下文环境。

在构造函数内绑定

生成实例的过程中,构造器函数 constructor() 必执行:

this.handleClick = this.handleClick.bind(this);

当我们调用handleClick时,handleClick方法内的this就指向bind参数里的this,即当前组件实例,这样每次生成实例执行构造器函数的时候都会重新bind,重新生成执行上下文环境。