JavaScript bind() 方法的实现
2018-03-31 11:00
375 查看
bind() 方法的特点
bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,
可以把除了第一个参数以外的其他参数都传递给下层的函数(这种技术称为“部分应用”,是“柯里化”的一种)注①
如果 bind() 返回的函数 作为构造函数使用,bind 时指定的 this 值会失效,但传入的参数有效。
new 调用返回的实例能够继承 绑定函数的原型 中的值
注①:
来自《你不知道的JavaScript》
关于局部应用与柯里化,引用 mqyqingfeng:
柯里化是将一个多参数函数转换成多个单参数函数,也就是将一个 n 元函数转换成 n 个一元函数。
局部应用则是固定一个函数的一个或者多个参数,也就是将一个 n 元函数转换成一个 n - x 元函数。
如果说两者有什么关系的话,引用 functional-programming-jargon 中的描述就是:Curried functions are automatically partially applied.
bind() 实现
方法一
Function.prototype.fakeBind = function(context) { if (typeof this !== "function") { throw new Error("Bind must be called on a function"); } let self = this; // 获得第一个参数以外的其他参数 let args = Array.prototype.slice.call(arguments, 1); let inner = function() { // 获得返回函数执行时被传入的参数 let innerArgs = Array.prototype.slice.call(arguments); // 1 new 情况下,this 指向实例。此时 bind 时指定的 this 值应予以失效; // 2 实例 instanceof 构造函数 返回值 true、false,确定是否为 new 调用; // 3 匿名函数直接调用 this 指向全局对象。此时应予以修改 this 的绑定 return self.apply( this instanceof inner ? this : context, args.concat(innerArgs) ); }; // inner.prototype = this.prototype // 按上面这么写的话,修改 返回函数原型对象(inner.prototype)的同时把 绑定函数的原型对象(this.prototype)也同时修改了。 // 用匿名函数做中转,this.protptype 就安全了。画个原型链的图就清楚了。 //注② let fNOP = function() {}; fNOP.prototype = this.prototype; inner.prototype = new fNOP(); return inner; };
注②
fNOP.prototype = this.prototype; 就是将 this.prototype 原型对象作为 fNOP.prototype 的原型对象,也就是 this.prototype 和 fNOP.prototype 指向同一个对象。
像 var f = new fNOP(); 之后找原型链上的属性,就是通过 f.proto,
因为 f.proto == fNOP.prototype == this.prototype
就会去 this.prototype 上找属性了。
方法二 ES6版
Function.prototype.fakeBindES6 = function(context, ...rest) { if (typeof this !== "function") { throw new Error("Bind must be called on a function"); } var self = this; return function inner(...args) { if (this instanceof inner) { // 当返回的内层函数作为构造函数使用,bind 时绑定的 this 失效。 // 即此处直接执行绑定函数,而不使用 apply 对 this 进行绑定 return new self(...rest, ...args); } // 当作为普通函数调用,this 指向传入的对象 return self.apply(context, rest.concat(args)); }; };
参考:https://github.com/mqyqingfeng/Blog/issues/12
相关文章推荐
- 用VC 6.0实现串行通信的三种方法
- Dephi 程序输入法自动切换最简单最好用的实现方法(被程序员杂志采纳,重新详细整理)
- php gzip压缩输出的实现方法
- 重定义键盘的两种实现方法
- 主机扫描程序实现方法
- 嵌入式Web视频点播系统实现方法
- Delphi系列谈之:Delphi中的静态属性及静态方法的实现
- 关于VC++中,两种自定义消息的发送与接收的方法实现进行说明。
- 一种实现数据库连接池的方法(JAVA)
- PowerBuilder中实现数据窗口打印预览通用方法
- ASP通过XMLDom在服务器端操作XML文件的主要方法和实现。
- 在BCB中把主菜单放到工具栏里后,实现自定义快捷键的方法
- HTML中树的实现方法
- Java 的JDBC 数据库连接池实现方法
- 在C++ Builder3下实现程序自动运行的方法
- 在 Windows 中实现 Java 本地方法
- 简单的在线升级的实现方法
- PHP实现文件上传的一种好方法
- 在WEB项目中多维下拉菜单的实现技巧和方法
- 如何在Java中实现远程方法调用