前言
前段时间用React写了些页面,但我们目前的项目还主要是Vue2,为防止忘得一干二净,又刷了遍基础知识。
在写类组件的时候,一不小心又碰到了this指向问题...
changeName () {
this.setState({
name: 'xxx'
})
}
这种写法会直接报this是undefined
一、this指向undefined问题
针对类组件中,事件处理函数中this为undefined问题,可以通过3种方法改变
1.箭头函数(这种方式应该较多一些)
changeName = () => {
this.setState({
name: ''
})
}
箭头函数没有this, 因此会向上找,直到window。
2.在调用事件处理函数时,直接通过箭头函数调用
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指向
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:
function fn (num) {
console.log(this, num)
}
fn()
可以看到this指向window,调用fn时,因为未传参,所以num为undefined。
case2:
var obj = {
a: 1
}
function fn (num) {
console.log(this, num)
}
fn.bind(obj, 1)()
由上图可以看到bind改变了this的指向,由window转为指向了obj。至于为什么后面还要加一个(), 是因为bind返回的是一个函数,而不是函数执行的结果。必须加一个(),函数才能执行起来。
case3:
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的原型上
function myBind () {
}
Function.prototype.myBind = myBind
step2: bind要改变this的指向,我们要把myBind的第一个参数设置成context,即改变this指向后的对象,默认值是window。
function myBind (context=window) {
}
Function.prototype.myBind = myBind
step3: bind要传入返回函数的参数,但这个参数的数量是不固定的,因此用扩展运算符处理
function myBind (context=window, ...outerArg) {
return function () {
}
}
Function.prototype.myBind = myBind
step4: 这里要介绍JS中的call()方法,call用于调用一个函数,并将指定的对象作为函数的上下文(this值),除了指定上下文外,还可以将参数作为一个列表传递给该方法。
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 组合起来。
重点就是如下代码:
function myBind(context=window,...outerArg){
let _this = this;
return function(...innerArg){
_this.call(context,...innerArg.concat(outerArg))
}
}
Function.prototype.myBind=myBind;
最后测试
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…