前言
前段时间用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...