学大家开头也放张图 ?
首先抛出结论:需要绑定this或者使用箭头函数,这完全是react的行为,本质上react的源码造成的。 写这篇文章,主要是因为看到有人错误地解释了这个问题,这会对不了解的人产生误导,所以我决定站出来简单写一下
网上错误的解释
// 情况1
const obj = {
name: 'yzy',
getName: function () {
console.log('name is', this.name)
}
}
obj.getName()
// 情况2
const obj = {
name: 'yzy',
getName: function () {
console.log('name is', this.name)
}
}
const _get = obj.getName
_get()
复制代码
很显然,在这个例子里面【情况1】是可以正常打印this.name的,但是【情况2】则无法打印this.name。原因很简单,当obj.getName被重新赋值给常量_get后,通过_get调用,那此时的this就是window了,所以不能正常打印。
网上的解释: <button onClick={this.btnClick}></button>
,因为this.btnClick赋值给了onClick这个变量,所以我们需要对this进行绑定,否则btnClick方法内的this指向就错了。
眨一看,还挺有道理!大家疯狂点赞,表示听懂了,学到了。然而真相并不如此
需要bind(this)的真正原因
说到真正原因,这里我们需要看一下源码
当我们给执行事件时,会触发以下源代码:
我们可以在源码中追溯invokeGuardedCallbackAndCatchFirstError这个函数,该函数接受的参数如下:
- 第一个参数是事件类型
- 第二个参数是事件执行函数
- 第三个参数是调用函数的上下文(默认为undefined)
- 第四个参数是event事件
通过追溯invokeGuardedCallbackAndCatchFirstError,我们得知最后执行的代码如下(这里就不截图了,直接复制源码):
function invokeGuardedCallbackProd<A, B, C, D, E, F, Context>(
name: string | null,
func: (a: A, b: B, c: C, d: D, e: E, f: F) => mixed,
context: Context,
a: A,
b: B,
c: C,
d: D,
e: E,
f: F,
) {
const funcArgs = Array.prototype.slice.call(arguments, 3);
try {
func.apply(context, funcArgs);
} catch (error) {
this.onError(error);
}
}
复制代码
这里的context就是执行函数绑定的this上下文内容,正常情况下它一直都是undefined。为了解决这个问题,我们只能再次修改它的this上下文内容以达到目的。
为什么我们用箭头函数就能解决这一问题呢,这是es6的知识点,在箭头函数中this引用的是定义箭头函数的上下文,可以理解为箭头函数中的this继承了他的上层作用域的this。
结尾
这是一篇心血来潮的文章,讲得可能不够详细,但我觉得如果那能理解bind方法和箭头函数的话,这篇文章足够让你明白【为什么react中的事件需要bind(this)或者使用箭头函数】。若文中有不严谨或错误的地方,欢迎指正。