• 也谈如何实现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))()
    }
    
  • 相关阅读:
    切割图像(一)概要
    无锁队列--基于linuxkfifo实现
    c++ virturn function -- 虚函数
    c friend -- 友元
    c++ anonymous union,struct -- 匿名联合体和机构体
    c++ anonymous namespace -- 匿名空间
    c++ inheritance -- 继承
    c++ 类名和enum时重复时要在类名前加class::
    c vs c++ in strcut and class
    C++ operator overload -- 操作符重载
  • 原文地址:https://www.cnblogs.com/zxuuu/p/12735316.html
Copyright © 2020-2023  润新知