zoukankan      html  css  js  c++  java
  • 也谈如何实现bind、apply、call

    我们知道,JavaScript的bind、apply、call是三个非常重要的方法。bind可以返回固定this、固定参数的函数包装;apply和call可以修改成员函数this的指向。实现bind、apply、call是前端面试的高频问题,也能让我们更好地理解和掌握JavaScript的函数的相关知识。本文将介绍如何自行实现bind、apply和call。

    前情提要

    本文先给出如下类定义和实例定义。

    // Person类,每个人有姓名,有打印姓名的方法
    function Person(_name) {
      this.name = _name
      this.sayMyName = function (postfix) {
        console.log(this.name + postfix)
      }
    }
    // 两个实例
    let alex = new Person('Alex')
    let bob = new Person('Bob')
    

    实现bind

    不妨先回顾一下bind的使用方法:

    let sayBobName = alex.sayMyName.bind(bob, '?')
    sayBobName() // Bob?
    

    可见:

    • bind返回一个函数副本(包装过的函数),固定this和实参。this可不指向调用者
    • bind是函数原型上的一个方法

    了解了这两点,就不难写出实现:

    function MyBind(context, ...args) {
      let that = this // this是调用者,也就是被包装的函数(alex.sayMyName)
      return function () { // 返回一个包装过的函数
        return that.call(context, ...args) // 其返回值是以context为this的执行结果
      }
    }
    Function.prototype.bind = MyBind
    

    实现call

    在实现bind的过程中我们用到了call。那么如何实现一个call?不妨也回顾一下call的使用方法:

    alex.sayMyName.call(bob, '!') // Bob!
    

    可见:

    • bind修改当前函数的this,可使其不指向调用者
    • 参数以...rest形式传入

    了解了这两点,也不难写出实现:

    function MyCall(context, ...args) {
      context._fn = this // this是调用者,也就是当前函数。此步给context绑上该函数
      // 有个细节问题是,可能需要备份原先的context._fn,避免意外覆盖
      let ret = context._fn(..args) // 模仿context自己调用_fn
      delete context._fn // 移除绑的函数
      return ret
    }
    Function.prototype.call = MyCall
    

    实现apply

    apply和call的作用相同,使用方法基本类似,唯一的不同是:

    • 参数以数组形式传入

    故可写出实现:

    function MyApply(context, args) {
      return MyCall(context, ...args)
    }
    Function.prototype.apply = MyApply
    

    稳定的三角

    从上面我们看出,apply和call可以实现bind,那么怎么用bind实现apply和call,从而打造这一铁三角关系呢?

        bind
      /            两两都可互相实现的三角形!
    call -- apply
    

    简单!立即执行这个函数副本就可以了!

    function AnotherMyCall(context, ...args) {
      return (this.bind(context, ...args))()
    }
    
  • 相关阅读:
    Roce ofed 环境搭建与测试
    Ubuntu 1804 搭建NFS服务器
    Redhat 8.0.0 安装与网络配置
    Centos 8.1 安装与网络配置
    SUSE 15.1 系统安装
    VSpare ESXi 7.0 基本使用(模板、iso、SRIOV)
    VSpare ESXi 7.0 服务器安装
    open SUSE leap 15.1 安装图解
    KVM虚拟机网卡连接网桥
    GitHub Action一键部署配置,值得拥有
  • 原文地址:https://www.cnblogs.com/zxuuu/p/12735316.html
Copyright © 2011-2022 走看看