废话:
前端也写了两年了,但是从以前到现在一直都不知道apply,call,bind是干什么的。或者说完全不知道应用场景,只是知道很多大佬靠这个实现了很多骚操作。
基本理解
这里是摘抄自菜鸟教程:www.runoob.com/w3cnote/js-…
call()、apply()、bind() 都是用来重定义 this 这个对象的!
三个参数的第一个参数都是你需要替换的this对象,后面才是参数传递。所以第一个参数是必须的,后面才是你需要处理的参数
call:第一个是this指向,后面是你要传入的参数
apply:第一个是this指向,第二个参数是数组
bind:第一个是this指向,后面是你要传入的参数,但是会返回一个新的函数
光看这里说真的谁都不理解,应用场景上也是懵逼的。所有的教程都是教你继承,和改变this指向。但是从实际业务出发的很少。
今天我终于把bind其中一个实际业务场景搞懂了,也是我最近实际理解了**高阶函数(传入一个函数,返回一个函数)**的意义和使用之后的使用。
一、举例:我们的查询列表数据接口
1、修改前
下面是我实际业务中的一段代码
const querList = async page => {
data.loading = true // 加载开始
try {
const result = await config.$Api.psy.fileManageList({
data: {
...data.queryParams,
pageNum: page,
pageSize: 20,
},
})
data.loading = false // 加载结束
const { size, current, total, records } = result // 数据处理
data.pagination = { // 分页数据
currentPage: current,
total: total,
pageSize: size,
}
console.log(records)
data.tableData = records.map(li => { // 数组再处理
const type = li.type
li.type = fileTypes.filter(ft => ft.value === type)[0].label
return li
})
} catch (e) {
data.loading = false // 加载结束
}
}
我个人使用了promise和async/await,不懂的赶紧补习去。
按我以前来说这基本上是差不多了,但是最近对高阶函数有了一番理解之后
2、业务上我们要注意一件事:
loading代表页面加载,比如element-ui的v-loading,或者全局蒙版那是必不可少的吧。但是我们loading这个参数会用很多次,每次都需要如上面一样,在开始定义为true,后面两处改为false。
并且我们实际很多场景中,可能不止一个参数,但是就是每次都是最基础的,比如数据初始化之类的。
当我们习惯了参数操作页面,控制等之后,参数开始泛滥了。我们发现参数开始到处都是,但是又必须定义状态,否则会报错。
利用高阶函数概念或者装饰器概念我们可以对代码进行拆分
3、修改后
基础修饰函数
async function baseHandler(callback) {
data.loading = true
try {
await callback()
data.loading = false
} catch (e) {
data.loading = false
}
}
业务列表函数
async function list(page = store.pagination.currentPage) {
try {
const result = await proxy.$Api.customerApi.userList({
data: {
...paramsHandler(),
pageNumber: page,
pageSize: 20,
},
})
const { totalElements, contents } = result
store.pagination = {
currentPage: page,
total: totalElements,
pageSize: 20,
}
data.tableData = contents.map(li => {
li.status = store.userType.filter(i => i.value === li.status)[0].label
return li
})
return Promise.resolve(result)
} catch (e) {
return Promise.reject(e)
}
}
组合之后
// 列表查询
function queryList() {
return baseHandler(list)
}
queryList(1)
这样的函数是能执行的。我们做到了高阶函数,和装饰器一样的语法。但是我们的参数1传不进去。
二、解决参数无法传入的问题
修改1
// 列表查询
function queryList(opt) {
return baseHandler(list(opt))
}
queryList(1)
那么基础装饰函数就会报错,提示不是一个函数。因为你的list已经执行了,返回了promise对象或者值。
async function baseHandler(callback) {
data.loading = true
try {
await callback() // 提示不是一个函数
data.loading = false
} catch (e) {
data.loading = false
}
}
不优雅的解决方式可以这样做
// 列表查询
function queryList(opt) {
return baseHandler(() => {
return list(opt) })
}
queryList(1)
这样是可以的但是我们还可以更加简单
三、bind函数登场
我们直接改为如下方式就可以
// 列表查询
function queryList(opt) {
return baseHandler(list.bind(this, opt))
}
queryList(1)
这样是不是非常省代码。我们做到了list不执行,但是也给了他的传入参数。
所以bind的使用方式我个人总结是:既可以修改this指向,也可以在不执行函数情况下,给予传入参数
我们也很容易理解了