有了对call()、apply()的前提分析,相信bind()我们也可以手到擒来。

参考前两篇:'对call()函数的分析' 和 '对apply()函数的分析',我们可以先得到以下代码:

Function.prototype.myBind = function(obj){
  // 判断调用对象是否为函数
  if(typeof this !== 'function'){
    console.error('type error!')
  }
  // 判断绑定的对象
  obj = obj || window;
}

bind()函数与call()函数参数的格式相同,不同的是bind()返回的是一个函数。

Function.prototype.myBind = function(obj){
  if(typeof this !== 'function'){
    console.error('type error!')
  }
  obj = obj || window;
  // 获取正确参数
  let args = [...arguments].slice(1);
  // 返回函数
  return function Fn(){};
}

使用bind()函数来对this进行绑定,可以之间在内部使用 apply() 。

Function.prototype.myBind = function(obj){
  if(typeof this !== 'function'){
    console.error('type error!')
  }
  obj = obj || window;
  let args = [...arguments].slice(1);
  return function Fn(){
    // 直接使用apply()
    return this.apply();
};
}

这个时候会发现,我们绑定的this是window,而不是我们想要的’this‘环境,可以使用that作为中间量。

Function.prototype.myBind = function(obj){
  if(typeof this !== 'function'){
    console.error('type error!')
  }
  obj = obj || window;
  // 在这里借助that
  that = this;
  let args = [...arguments].slice(1);
  return function Fn(){
    return that.apply();
};
}

然后我们需要考虑apply()中传递的参数,这里我们使用数组的concat()方法,得到apply中传递的数组。

Function.prototype.myBind = function(obj){
  if(typeof this !== 'function'){
    console.error('type error!')
  }
  obj = obj || window;
  that = this;
  let args = [...arguments].slice(1);
  return function Fn(){
// 传递两个参数(绑定对象,数组)
    return that.apply(obj,args.concat(...arguments));
};
}

最后需要判断函数作为构造函数的情况,这个时候需要传入当前函数的 this 给 apply 调用,其余情况都传入指定的上下文对象。

Function.prototype.myBind = function(obj){
  if(typeof this !== 'function'){
    console.error('type error!')
  }
  obj = obj || window;
  that = this;
  let args = [...arguments].slice(1);
  return function Fn(){
// 根据调用方式,传入不同绑定值
    return that.apply(
      this instanceof Fn ? this : obj,
      args.concat(...arguments));
};
}

最后通过一个例子,来验证是否达到bind()的功能要求。

Function.prototype.myBind = function(obj){
  if(typeof this !== 'function'){
    console.error('type error!')
  }
  obj = obj || window;
  that = this;
  let args = [...arguments].slice(1);
  return function Fn(){
    return that.apply(
      this instanceof Fn ? this : obj,
      args.concat(...arguments)
    );
  }
}
let dog = {
  name: '狗',
  eat(food1, food2) {
    console.log(this.name + '爱吃' + food1 + food2);
  }
}
let cat = {
  name: '猫',
}
dog.eat.bind(cat, '鱼', '肉')(); // 猫爱吃鱼肉
dog.eat.mybind(cat, '鱼', '肉')(); // 猫爱吃鱼肉

理解并手写 bind() 函数的更多相关文章

  1. 理解并手写 call() 函数

    手写自己的call,我们要先通过call的使用,了解都需要完成些什么功能? call()进行了调用,是个方法,已知是建立在原型上的,使用了多个参数(绑定的对象+传递的参数). 我们把手写的函数起名为m ...

  2. 手写bind函数

    实现bind函数 参考MDN提供的Polyfill方案 Function.prototype.myBind = function(context){ //这里对调用者做一个判断,如果不是函数类型,直接 ...

  3. 理解并手写 apply() 函数

    apply()函数,在功能上类似于call(),只是传递参数的格式有所不同. dog.eat.call(cat, '鱼', '肉'); dog.eat.apply(cat, ['鱼', '肉']); ...

  4. 前端面试题整理——手写bind函数

    var arr = [1,2,3,4,5] console.log(arr.slice(1,4)) console.log(arr) Function.prototype.bind1 = functi ...

  5. WPF启动流程-自己手写Main函数

    WPF一般默认提供一个MainWindow窗体,并在App.Xaml中使用StartupUri标记启动该窗体.以下通过手写实现WPF的启动. 首先先介绍一下VS默认提供的App.Xaml的结构,如下图 ...

  6. 优雅手撕bind函数(面试官常问)

    优雅手撕bind函数 前言: 为什么面试官总爱让实现一个bind函数? 他想从bind中知道些什么? 一个小小的bind里面内有玄机? 今天来刨析一下实现一个bind要懂多少相关知识点,也方便我们将零 ...

  7. python 精华梳理(已理解并手写)--全是干货--已结

    基础部分 map,reduce,filter,sort,推导式,匿名函数lambda , 协程,异步io,上下文管理 自定义字符串转数字方法一不使用reduce import re def str2i ...

  8. C++之手写strlen函数

    代码: int strlen(const char *str){ assert(str!=NULL); intlen=; while((*str++)!='\0') len++; return len ...

  9. js面试题之手写节流函数和防抖函数

    函数节流:不断触发一个函数后,执行第一次,只有大于设定的执行周期后才会执行第二次 /* 节流函数:fn:要被节流的函数,delay:规定的时间 */ function throttle(fn,dela ...

随机推荐

  1. json解析出现:java.lang.ClassCastException: net.sf.ezmorph.bean.MorphDynaBean cannot be cast to XXX

    感谢大佬:https://blog.csdn.net/one_ink/article/details/99817676 一.出错原因 当我们利用json解析中的toBean方法时,如果它的属性里面包含 ...

  2. 使用MediaPlayer框架实现简单音乐播放器-陈棚

    该项目需要使用MediaPlayer框架,因此程序需要先为该项目添加MediaPalyer框架,并在上面控制器类的实现部分使用#import<MediaPlayer/MediaPlayer.h& ...

  3. 简单实现Tabbar的隐藏显示动画 By H罗

    简单实现Tabbar的隐藏显示动画 Hide Tabbar Controller with Animation - (void)setTabBarVisible:(BOOL)visible anima ...

  4. JSP页面 CTRL+F 功能实现

    .res { color: rgba(255, 0, 0, 1) } .result { background: rgba(255, 255, 0, 1) } --- js 部分 var oldKey ...

  5. Solution -「AGC 016F」Games on DAG

    \(\mathcal{Description}\)   Link.   给定一个含 \(n\) 个点 \(m\) 条边的 DAG,有两枚初始在 1 号点和 2 号点的棋子.两人博弈,轮流移动其中一枚棋 ...

  6. Netty高级应用及聊天室实战

    Netty 高级应用 1. 编解码器 概念:在网络应用中,需要实现某种编解码器.将原始字节数据与自定义消息数据进行相互转换.网络中都是以字节码的形式传输的. 对Netty而言,编解码器由两部分组成:编 ...

  7. SpringCloud微服务实战——搭建企业级开发框架(三十七):微服务日志系统设计与实现

      针对业务开发人员通常面对的业务需求,我们将日志分为操作(请求)日志和系统运行日志,操作(请求)日志可以让管理员或者运营人员方便简单的在系统界面中查询追踪用户具体做了哪些操作,便于分析统计用户行为: ...

  8. PHP获取用户IP地址

    PHP获取访问者IP地址 这是一段 PHP 代码,演示了如何获得来访者的IP address. <?php//打印出IP地址:echo (GetIP());function GetIP()  / ...

  9. WMI简介和Event驻留

      WMI (Windows Management Instrumentation,Windows管理规范) 从Windows 2000开始被包含于操作系统后,就一直是Windows操作系统的一部分. ...

  10. 暑假撸系统3- petty热更新 mybatis自动填充时间字段!

    经过了昨天纠结技术选型,和一大堆xml配置,终于把架子搭好了.因为最近一次做java项目也在好多年以前了(毕竟用了pytohn以后谁也不想再回来java了),java的生态发生了长足的进步,本来想从原 ...