bind方法的使用,配合实际应用场景

1,212 阅读2分钟

废话:

前端也写了两年了,但是从以前到现在一直都不知道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指向,也可以在不执行函数情况下,给予传入参数

我们也很容易理解了

四、谢谢阅读