有了对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. asp.net core 中的各种路径

    1.获取完整网址URL 方法一:先引用"using Microsoft.AspNetCore.Http.Extensions;",然后直接用"Request.GetDis ...

  2. Android 存储到SD卡,获取SD的大小及可用空间

    使用Sdcard注意事项:     1.权限问题:             <uses-permission android:name="android.permission.WRIT ...

  3. Java 内置注解简单理解

    感谢原文作者:yejg1212 原文链接 https://www.cnblogs.com/yejg1212/p/3187362.html https://www.cnblogs.com/yejg121 ...

  4. Git Push 免输 用户名和密码

    前言 在大家使用github的过程中,一定会碰到这样一种情况,就是每次要push 和pull时总是要输入github的账号和密码,这样不仅浪费了大量的时间且降低了工作效率.在此背景下,本文在网上找了两 ...

  5. K8s多节点部署+负载均衡+keepalived ——囊萤映雪

    K8s多节点部署+负载均衡+keepalived --囊萤映雪 1.多节点master2 部署 2.负载均衡部署+keepalived 1.多节点master2部署: #从master01节点上拷贝证 ...

  6. 还在做廉价的劳动力?部署PXE实现Kickstart无人值守安装

    搭建PXE实现Kickstart无人值守安装 1.搭建PXE远程安装服务器 2.实现kicstart无人值守安装 1.PXE介绍及搭载: PXE是有Intel公司开发的网络引导技术,工作在Client ...

  7. 枚举和注解@override、@Deprecated、@SuppressWarnings

    一.枚举 简介: 1)枚举对应英文(enumeration,简写 enum) 2)枚举是一组常量的集合. 3)可以这里理解:枚举属于一种特殊的类,里面只包含一组有限的特定的对象. 实现方式: 1.自定 ...

  8. Solution -「CF 793G」Oleg and Chess

    \(\mathcal{Description}\)   Link.   给一个 \(n\times n\) 的棋盘,其中 \(q\) 个互不重叠的子矩阵被禁止放棋.问最多能放多少个互不能攻击的车.   ...

  9. linux大工程 - 我要一个属于自己的回收站

    我要开始装13了 'rm -rf 是一个很"粗鲁"的命令,就像windows的shift+delete,删除的文件是无法找回的(当然,除了数据恢复软件,但是很麻烦,很费时)' '为 ...

  10. EasyX库简单中文手册

    EasyX库简单中文手册 作者: 时间: 2021/2/2 第一个例程 #include <graphics.h> // 图像相关库 #include <conio.h> // ...