前言

bind 和 call/apply 一样,都是用来改变上下文 this 指向的,不同的是,call/apply 是直接使用在函数上,而 bind 绑定 this 后返回一个函数(闭包),如下:

var obj = {init: 1,add: function(a, b) {return a + b + this.init;}
}
obj.add(1, 2); // 4var plus = obj.add;
plus(3, 4); // NaN,因为 this.init 不存在,这里的 this 指向 window/globalplus.call(obj, 3, 4) // 8
plus.apply(obj, [3, 4]); // 8, apply 和 call 的区别就是第二个参数为数组
plus.bind(obj, 3, 4); // 返回一个函数,这里就是 bind 和 call/apply 的区别之一,bind 的时候不会立即执行
plus.bind(obj, 3, 4)(); // 8 

有趣的测试

测试一

假如,call、apply、bind 第一个参数是 null 或者是 undefined 会是什么结果?

function test() {console.log(this);
}
test(); // this === window// call
test.call(null); // this === window
test.call(undefined); // this === window// apply
test.apply(null); // this === window
test.apply(undefined); // this === window// bind
test.bind(null)(); // this === window
test.bind(undefined)(); // this === window

上述测试只是在非严格的模式下进行,感兴趣的话可以测试一下严格模式。

测试二

前面知道 bind 是返回一个函数,它的执行很像函数柯里化的一个过程,如下:

// 柯里化
function test(x) {return function(y){return x + y;}
};
test(1)(2); // 3// bind
function test2(a, b) {return a + b;
}
test2.bind(null, 1)(2); // 3

这是是 bind 的一个特殊用法:预设参数,更好的例子如下:

function list() {return Array.prototype.slice.call(arguments);
}var list1 = list(1, 2, 3); // [1, 2, 3]// Create a function with a preset leading argument
var leadingThirtysevenList = list.bind(undefined, 37);var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]

测试三

bind 返回一个函数,那么这个函数当做构造函数会发生什么?

function Test3(a, b) {this.a = a;this.b = b;
}
Test3.prototype.add = function () {return this.a + this.b;
}// 如果不用 bind,正常来说这样处理
var t1 = new Test3(1, 2);
t1.add(); // 3, this 指向 t1// 使用 bind
var NewTest3 = Test3.bind(null, 3);
var t2 = new NewTest3(4);
t2.add(); // 7, this 指向 t2

将绑定函数当做构造函数使用,bind 提供的 this 指向无效,但是还是可以预设参数。

bind 的实现

通过以上测试,知道 bind 的用法及原理,还是希望能动手一步一步实现一下:

// 利用 apply 改变 this 指向
Function.prototype.bind = function(context) {var that = this;return function() {return that.apply(context, arguments);}
}

上述实现只能传递一个参数(context),原生的 bind 方法可以传入多个参数,作如下修改:

// 将 bind 方法的参数提取出来拼接到返回的闭包函数中
Function.prototype.bind = function(context) {var that = this;var args = Array.prototype.slice.call(arguments, 1);return function() {// 预设参数一定是 args 在前拼接return that.apply(context, args.concat(Array.prototype.slice.call(arguments))) ;}
}

修改之后可以传多个参数了,测试一和测试二的场景也满足,但是测试三的场景不满足(不能作为构造函数):

Function.prototype.bind = function(context) {var that = this;var args = Array.prototype.slice.call(arguments, 1);var bound = function() {if(this instanceof bound) { // 如果是作为构造函数,那么第一个参数 context 就不需要了return that.apply(this, args.concat(Array.prototype.slice.call(arguments)));} else {return that.apply(context, args.concat(Array.prototype.slice.call(arguments))) ;}}// 维护原型关系if(this.prototype) {bound.prototype = this.prototype;}return bound;
}

好了,一个简单版的 bind 完成,满足上面三个测试项。

总结

平时我用到的最多的场景,就是简单的使用 bind 来改变 this 指向,那样做和 call/apply 没什么区别,只是一个延迟执行的作用,以为 bind 很简单,现在看来,其实并不简单。。。

  • 参考 MDN

bind 用法及简单实现原理相关推荐

  1. 配置BIND 9 DNS Views 的原理和需求

    配置BIND 9 DNS Views 的原理和需求 -------------------------------------------------------------------------- ...

  2. MyBatis接口的简单实现原理

    MyBatis接口的简单实现原理 用过MyBatis3的人可能会觉得为什么MyBatis的Mapper接口没有实现类,但是可以直接用? 那是因为MyBatis使用Java动态代理实现的接口. 这里仅仅 ...

  3. 求介绍matlab函数用法的书,MATLAB初学者教程--函数用法的简单介绍

    1.4 函数用法的简单介绍 1.4.1什么是函数 似乎很多人一听到函数这个词就会想到数学中的某个概念,然后对于恐惧数学的同学就开始打退堂鼓.在matlab当中到处可以用到函数,它的出现可以让我们用很简 ...

  4. SQL注入详解和简单绕过原理

    1.什么是SQL 结构化查询语言(Structured Query Language)简称SQL SQL使我们有能力访问数据库 2.什么是SQL注入 用户提交的数据可以被数据库解析执行 如果用户随随便 ...

  5. boost::lambda::bind用法的测试程序

    boost::lambda::bind用法的测试程序 实现功能 C++实现代码 实现功能 boost::lambda::bind用法的测试程序 C++实现代码 #include <boost/c ...

  6. boost::function模块boost::lambda::bind用法的测试程序

    boost::function模块boost::lambda::bind用法的测试程序 实现功能 C++实现代码 实现功能 boost::function模块boost::lambda::bind用法 ...

  7. php 数组重新打乱_PHP 将数组打乱 shuffle函数的用法及简单实例

    shuffle() PHP shuffle() 函数随机排列数组单元的顺序(将数组打乱).本函数为数组中的单元赋予新的键名,这将删除原有的键名而不仅是重新排序. 语法: bool shuffle ( ...

  8. (转)简单代码生成器原理剖析(二)

    原文地址:http://www.cnblogs.com/OceanEyes/archive/2012/03/08/codebuilder.html 上篇<简单代码生成器原理剖析(一)>分析 ...

  9. 数量周期 复杂现象背后的推动力,可能是极其简单的原理。科学的目标之一就是发现纷 繁复杂的自然现象背后的简单法则。爱因斯坦的相对论是这方面的典范例证。

    /*数量周期* 复杂现象背后的推动力,可能是极其简单的原理.科学的目标之一就是发现纷繁复杂的自然现象背后的简单法则.爱因斯坦的相对论是这方面的典范例证.很早的时候,生物学家观察某区域某种昆虫的数量(称 ...

最新文章

  1. Qunee for HTML5 V2.5新版本发布
  2. iis8.5部署net项目
  3. 一篇文章讲懂Vmware网卡配置,解决常见问题
  4. oracle一体机高水位,oracle 移动高水位:
  5. Ubuntu18.04上安装RTX 2080Ti显卡驱动
  6. java python c++比喻图_Java/Python/PHP/C++图文详解它们之间的尿性
  7. Go 语言“助力”恶意软件?仅 4 年基于 Go 的恶意软件数就激增 2000%!
  8. jsp和mysql答辩_如何应对JSP连接MySQL数据库问题_网站数据库怎么连接到网页答辩问题...
  9. ​​​​​​​​CloudMounter:挂载云存储作为在 Mac 的本地磁盘
  10. 16.卷2(进程间通信)---Sun RPC
  11. 可视化大屏设计尺寸_大屏数据可视化设计规律
  12. cfa考试用计算机,cfa考试一定要用专用计算器么
  13. 利用Expect实现telnet自动登录并执行command
  14. 学习笔记 | 深度学习相关研究与展望 Review of deep learning
  15. 计算机毕设(附源码)JAVA-SSM交通事故证据交易平台
  16. 手机储存卡数据怎么恢复
  17. R语言入门第一集 R语言、RTools、RStudio的简介、安装与使用
  18. JNLP文件详细说明
  19. 基于Kinect体感器控制的机械臂项目记录
  20. python代码格式怎么写比较好

热门文章

  1. 【浏览器直播源抓取】浏览器抓取真实直播源地址(2022/11/16)
  2. 因果信号的傅里叶变换_信号与系统实验报告3实验3 傅里叶变换及其性质
  3. linux对已有分区进行扩容
  4. 【笔记】IP地址详解、Linux网络及常用命令
  5. BED文件与bedtools简介
  6. 【OpenCV入门学习--python】图像的矩Image Moments
  7. Android——仿京东秒杀
  8. BZOJ3693:圆桌会议(Hall定理)
  9. 这10个小技巧,让你的Python数据分析加速50%!
  10. 数据库Geometry字段操作