加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

React中的事件处理为什么要bind this?

发布时间:2020-12-15 20:40:24 所属栏目:百科 来源:网络整理
导读:个人总结: ? 问: 请给我讲一下React中的事件处理为什么要bind this? ? ? ? ? 答:好的。好的, 比如说我写了一个类组件,有个onClick属性 ,onClick={ this.fun },如果不bind肯定是会炸裂的,下面讲一下为什么要bind this: ? ? 首先我们知道React是通过创建虚

个人总结:

?

问: 请给我讲一下React中的事件处理为什么要bind this?

?

?

?

?

答:好的。好的,比如说我写了一个类组件,有个onClick属性 ,onClick={ this.fun },如果不bind肯定是会炸裂的,下面讲一下为什么要bind this:

? ? 首先我们知道React是通过创建虚拟DOM 然后将虚拟DOM生成真实的DOM 最后插入到页面中,

? ? 而React生命周期中render方法的作用就是将虚拟DOM渲染成真实DOM

? ? ?看一下这篇文章?https://github.com/hujiulong/blog/issues/4

? ? 这里提到了render的实现 render将"on+大写字母"开头的事件属性 转化为"on+小写字母"开头的属性 并生成真实DOM,生成真实DOM的同时

? ? 把这个函数赋值过去。???

?

?

预备知识点:JS中的this是由函数调用者调用的时候决定的。?

? ?obj:{

? ? ? ?fun:function(){ console.log(this) }

? ? ? }?

? obj.fun()? ?//obj

?

let var = obj.fun()

? var()? ? ? // window||undefined

?

?

? ?在类组件的render函数中 将函数fun赋给真实的属性的时候 有点类似于做了这样的操作:

?

class Cat { sayThis () { console.log(this); // 这里的 `this` 指向谁? } exec (cb) { cb(); } render () { this.exec(this.sayThis); } }
const tom = new Cat(); tom.render(); // 输出结果是什么?

?

当把一个函数作为callback传递给另一个函数的时候,这个函数的this一定是会丢失的,

因为相当于是 let var = fun() { ..} ; var();

所以会出现这种问题。

?

延伸一下,为什么React没有自动的把bind集成到render方法中呢?

答:因为render多次调用每次都要bind会影响性能。

?

==========================================================

?

知乎大佬-dmumatt原回答:

?

代码一:

// 使用 ES6 的 class 语法 class Cat { sayThis () { console.log(this); // 这里的 `this` 指向谁? } exec (cb) { cb(); } render () { this.exec(this.sayThis); } } const tom = new Cat(); tom.render(); // 输出结果是什么?

?

代码二:

const jerry = { sayThis: function () { console.log(this); // 这里的 `this` 指向谁? },exec: function (cb) { cb(); },render: function () { this.exec(this.sayThis); },} jerry.render(); // 输出结果是什么?


?

代第一段代码的结果是 undefined ,这和第一节中 React 出现的结果完全一致。这代表 this 指向了 undefined 。其实是 JS 的行为而并非 React。

第二段代码的结果是,你所使用的环境里面的全局对象——在浏览器中就是 window 对象,在 Node.js 中就是 global 对象。

你看到输出结果的时候,一定感到很困惑吧?到底 this 干了什么??


JS 中的 this

this 不指向定义它的函数的那个对象的情形

var name = ‘Global‘ const fish = { name: ‘Fish‘,greet: function() { console.log(‘Hello,I am ‘,this.name); } }; fish.greet(); // Hello,I am Fish const greetCopy = fish.greet; greetCopy(); // Chrome: Hello,I am Global // Node.js: Hello,I am undefined

当你使用“点”操作符 . 来调用 greet 函数的时候,fish.greet()this 指向了 fishfish 正是定义了 greet 方法的那个对象。在这种情况下,我们称 fish 是这个函数的调用者

事实上,fish.greet 在内存中只是一个普通的函数。不管它是在什么对象中定义的,它都可以和普通的函数一样,赋值给另一个变量,比如前面的 greetCopy 。如果你用 console.log 打印 console.log(fish.greet) 或者 console.log(greetCopy) ,控制台输出的结果都是一样的。

console.log(fish.greet); // function () { … } console.log(greetCopy); // function () { … }

如果你不用调用者显式地调用一个函数,JS 的解释器就会把全局对象当作调用者。所以 greetCopy() 这个语句在 Chrome 中的行为就和 greetCopy.call(window) 是一样的,在 Node.js 中就和 greetCopy.call(global) 是一样的。

但是有一种例外,如果你使用了严格模式,那么没有显式的使用调用者 的情况下, this 永远不会自动绑定到全局对象上。如果此时你调用 greetCopy ,你就会得到报错,因为这时候 this 不指向任何对象,this 这时候就是 undefined

‘use strict‘; var name = ‘Global‘ const fish = { name: ‘Fish‘,I am Global const greetCopy = fish.greet; greetCopy(); // Uncaught TypeError: Cannot read property ‘name‘ of undefined

注意,在上面这种情况下,greetCopy 在 Chrome 中和在 Node.js 中行为不太一样。正如你看到的那样,在 Node.js 中,this.name 的值是 undefined 。在浏览器中,如果你在最外层作用于定义了一个变量,它就会自动变成全局对象的一个属性。相反,在 Node.js 中,最外层对象不会自动被赋给全局对象,除非你显式地使用 global.name = ‘Global‘

如果我想使用另一个对象作为调用者来调用 fish.greet ,我该怎么做?这时候就要用到 Function.prototype.call

// 前面代码一的上下文 const pig = { name: "Pig" }; fish.greet.call(pig); // Hello,I am Pig

call 方法强制性地把 fish.greet调用者绑定到了 pig 对象上,pig 这时候用作 this 方法的参数。

?

回调函数中的 this

回调函数简单的来说,就是把一个函数作为另一函数的参数,并且在另一个函数执行的时候调用这个函数。看一下下面的例子:

var name = ‘Global‘; const matt = { name: "Matt",sayName: function () { console.log(this.name); } } function exec(cb) { cb(); } exec(matt.sayName); // `Global` (浏览器),`undefined` (Node.js)

如果你阅读了上面的章节,这个输出结果对你来说就很好理解了。我们来看一下在解释器调用 exec() 函数的时候都做了什么。

当这个程序运行到 exec 函数的时候,实参 matt.sayName 被传递给了形参 cb 。这就和前面的章节中说的赋值语句的情况类似:const greetCopy = fish.greet; 。这里 cb 在调用的时候并没有显式的调用者,所以此时,this非严格模式下就会指向全局对象,在严格模式下就会指向 undefined

我们来看一下另一个很相似的情形。思考一下结果是什么?

const jerry = { sayThis: function () { console.log(this); // `this` 指向什么? },} jerry.render(); // 输出结果是什么?

是的!你在上一章中看到了这个例子了。你现在一定知道了为什么输出结果是全局对象了吧!

即使我们使用点操作符. 来显式地调用 exec 方法,然而 cb 函数仍然没有一个显式的调用者。因此,你就会看到 this 指向了全局对象。

下面这句话非常重要!一般人可能不知道

如果你使用了 ES6 的 class 语法,所有在 class 中声明的方法都会自动地使用严格模式

当你使用 onClick={this.handleClick}来绑定事件监听函数的时候,handleClick 函数实际上会作为回调函数,传入 addEventListener() 。这就是为什么你在 React 的组件中添加事件处理函数为什么会得到 undefnied 而不是全局对象或者别的什么东西。

箭头函数

箭头函数使得 this 更简单和直接。

关于箭头函数的资料其实很多,在这里我就不多说了。你只要记住一个规则就足够了,如果你仔细阅读了上文,你应该能理解这个规则

this 永远绑定了定义箭头函数所在的那个对象

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读