由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...

相关推荐
爱学习的程序媛1 小时前
【Web前端】JavaScript设计模式全解析
前端·javascript·设计模式·web
小码哥_常1 小时前
从SharedPreferences到DataStore:Android存储进化之路
前端
老黑1 小时前
开源工具 AIDA:给 AI 辅助开发加一个数据采集层,让 AI 从错误中自动学习(Glama 3A 认证)
前端·react.js·ai·nodejs·cursor·vibe coding·claude code
jessecyj1 小时前
Spring boot整合quartz方法
java·前端·spring boot
苦瓜小生2 小时前
【前端】|【js手撕】经典高频面试题:手写实现function.call、apply、bind
java·前端·javascript
天若有情6732 小时前
前端HTML精讲03:页面性能优化+懒加载,搞定首屏加速
前端·性能优化·html
踩着两条虫2 小时前
AI驱动的Vue3应用开发平台深入探究(十):物料系统之内置组件库
android·前端·vue.js·人工智能·低代码·系统架构·rxjava
swipe2 小时前
AI 应用里的 Memory,不是“保存聊天记录”,而是管理上下文预算
前端·llm·agent
慧一居士3 小时前
nuxt3 项目和nuxt4 项目区别和对比
前端·vue.js
威联通安全存储3 小时前
破除“重前端、轻底层”的数字幻象:如何夯实工业数据的物理底座
前端·python