由React类组件中的this指向问题,引发的一系列学习

前言

前段时间用React写了些页面,但我们目前的项目还主要是Vue2,为防止忘得一干二净,又刷了遍基础知识。

在写类组件的时候,一不小心又碰到了this指向问题...

kotlin 复制代码
   changeName () {
       this.setState({
           name: 'xxx'
       })
   }

这种写法会直接报this是undefined

一、this指向undefined问题

针对类组件中,事件处理函数中this为undefined问题,可以通过3种方法改变

1.箭头函数(这种方式应该较多一些)

javascript 复制代码
   changeName = () => {
       this.setState({
           name: ''
       })
  }
   

箭头函数没有this, 因此会向上找,直到window。

2.在调用事件处理函数时,直接通过箭头函数调用

scala 复制代码
import React from "react"
class Pfs extends React.Component {
  // 定义组件状态
  state = {
    name: 'cp teacher'
  }
  changeName () {
    this.setState({
      name: '测试更改state中的name'
    })
  }
  render () {
    return (
      <div>This is testComponent
        当前name为: {this.state.name}
        <button onClick={() => this.changeName()}>更改name</button>
      </div>
    )
  }
}
export default Pfs

3.使用bind修改this指向

scala 复制代码
import React from "react"
class Pfs extends React.Component {
  constructor() {
    super()
    this.changeName = this.changeName.bind(this)
  }
  // 定义组件状态
  state = {
    name: 'cp teacher'
  }
  changeName () {
    this.setState({
      name: '测试更改state中的name'
    })
  }
  render () {
    return (
      <div>This is testComponent
        当前name为: {this.state.name}
        <button onClick={this.changeName}>更改name</button> //注意,这里的调用方式也变了
      </div>
    )
  }
}
export default Pfs

二、JS中的bind

case1:

php 复制代码
function fn (num) {
    console.log(this, num)
}
fn()

可以看到this指向window,调用fn时,因为未传参,所以num为undefined。

case2:

javascript 复制代码
var obj = {
  a: 1
}
function fn (num) {
  console.log(this, num)
}
fn.bind(obj, 1)()

由上图可以看到bind改变了this的指向,由window转为指向了obj。至于为什么后面还要加一个(), 是因为bind返回的是一个函数,而不是函数执行的结果。必须加一个(),函数才能执行起来。

case3:

javascript 复制代码
var obj = {
  a: 1
}
function fn (num1,num2) {
  console.log(this, num1,num2)
}
fn.bind(obj, 1)(2)

由上图可知,传参可以分批传。

二、自己实现bind

参考链接:zhuanlan.zhihu.com/p/266798352

step1: 由于bind是由函数调用,因此自己实现的bind要加在function的原型上

javascript 复制代码
function myBind () {

}
Function.prototype.myBind = myBind

step2: bind要改变this的指向,我们要把myBind的第一个参数设置成context,即改变this指向后的对象,默认值是window。

ini 复制代码
function myBind (context=window) {

}
Function.prototype.myBind = myBind

step3: bind要传入返回函数的参数,但这个参数的数量是不固定的,因此用扩展运算符处理

javascript 复制代码
function myBind (context=window, ...outerArg) {
    return function () {
    
    }
}
Function.prototype.myBind = myBind

step4: 这里要介绍JS中的call()方法,call用于调用一个函数,并将指定的对象作为函数的上下文(this值),除了指定上下文外,还可以将参数作为一个列表传递给该方法。

vbnet 复制代码
function.call(thisArg, arg1, arg2, ...)

thisArg: 在函数执行时作为this值绑定到函数的对象

arg1, arg2,...要传递给函数的参数。

!!!! 在用 bind 的时候,比如 fn.bind(),我们返回的函数其实就是 fn 本身,只是改了 this 而已 ,所以,为了获取到 fn,我们需要在 myBind 里用 this 拿到这个 fn。需要注意的是,匿名函数中的 this 指向并不是 fn,而是 window 。另一点是,myBind 自己可以传参,内部的匿名函数也可以,根据 例3,我们了解到 bind 可以分批传参的特点,因此,我们需要把外部参数和内部参数利用 concat 组合起来

重点就是如下代码:

javascript 复制代码
function myBind(context=window,...outerArg){
let _this = this;
return function(...innerArg){
               _this.call(context,...innerArg.concat(outerArg))
           }
       }
Function.prototype.myBind=myBind;

最后测试

javascript 复制代码
function myBind(context=window,...outerArg){
  let _this = this;
  console.log('_this', _this)  //f fn(num){console.log(this,num)}
  return function(...innerArg){
      _this.call(context,...innerArg.concat(outerArg))
  }
}
Function.prototype.myBind=myBind;

function fn(num){
  console.log(this,num)
}
fn.myBind({a:1},50)();

其中,myBind的这套方法对应一个专有名词,叫柯里化函数思想

二、柯里化

参考链接: juejin.cn/post/701656...

相关推荐
y先森5 小时前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy5 小时前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu10830189115 小时前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿6 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡7 小时前
commitlint校验git提交信息
前端
虾球xz8 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇8 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒8 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员8 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐8 小时前
前端图像处理(一)
前端