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

相关推荐
m0_5485147717 分钟前
前端Pako.js 压缩解压库 与 Java 的 zlib 压缩与解压 的互通实现
java·前端·javascript
AndrewPerfect17 分钟前
xss csrf怎么预防?
前端·xss·csrf
Calm55020 分钟前
Vue3:uv-upload图片上传
前端·vue.js
浮游本尊25 分钟前
Nginx配置:如何在一个域名下运行两个网站
前端·javascript
m0_7482398325 分钟前
前端bug调试
前端·bug
m0_7482329228 分钟前
[项目][boost搜索引擎#4] cpp-httplib使用 log.hpp 前端 测试及总结
前端·搜索引擎
新中地GIS开发老师33 分钟前
《Vue进阶教程》(12)ref的实现详细教程
前端·javascript·vue.js·arcgis·前端框架·地理信息科学·地信
m0_7482495435 分钟前
前端:base64的作用
前端
html组态41 分钟前
web组态可视化编辑器
前端·物联网·编辑器·web组态·组态·组态软件
~央千澈~1 小时前
如果你的网站是h5网站,如何将h5网站变成小程序-除开完整重做方法如何快速h5转小程序-h5网站转小程序的办法-优雅草央千澈
前端·apache