JS 的apply call bind的实现
思路
三个函数简介
apply(this,[arg1,arg2…]);
call(this,arg1,arg2);
call和apply相似目的都是为了将执行函数的this值改变,后面的参数是为了填入参数
bind(this,arg1,arg2,arg3);
bind的主要目的是返回一个绑定了this的新的函数,后面的参数是填充进去的参数作为默认参数。
下面给一个阮一峰老师的例子:
1 2 3 4 5 6 7 8
| var d = new Date(); d.getTime() // 1481869925657 //重写一个打印时间的函数 var print = d.getTime; print() // Uncaught TypeError: this is not a Date object.
var print = d.getTime.bind(d); //一个新的示例应该绑定原来的Date对象 print() // 1481869925657
|
主要思路
apply 和call 是返回执行后的结果,所以在要绑定对象的对象内绑定一个函数执行即可。参数问题使用arguments导出一个数组将剩余的参数传入。
注:arguments是一个类似数组的东西,只有索引和长度。详见MDN。在不手动的情况下可以使用Array.prototype.slice.call(arguments);但是这里是手动情况所以要一点点读取导出。
bind 的话,对于执行上面使用eval直接运算函数。返回函数的时候使用一个闭包
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| <!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8"> </head> <body> <script type="text/javascript"> Function.prototype.myCall = function (obj) { if (obj==null){ obj=window; } obj._fn_ = this; var args = [],len = arguments.length; for (var i=1;i<len;i++){ args.push(arguments[i]); } var result = eval('obj._fn_('+args+')'); delete obj._fn_; return result; }; Function.prototype.myApply = function(obj,arr){ if (obj==null){ obj=window; } obj._fn_ = this; var result = eval('obj._fn_('+arr+')'); delete obj._fn_; return result; } Function.prototype.myBind = function(obj){ if (obj==null){ obj=window; } obj._fn_ = this; var args = [],len = arguments.length; for (var i=1;i<len;i++){ args.push(arguments[i]); }
var result = function(){ var args2 = [],len = arguments.length; for (var i=0;i<len;i++){ args2.push(arguments[i]); } return eval('console.log(obj);obj._fn_('+args.concat(args2)+')'); }; return result; }; var a = { l:1, output:function (a) { console.log(Array.prototype.join.call(arguments,"-")); return this.l; } }; var b = { l:2 }; var c= { l:3 }; console.log(a.output.myApply(b,[1,2,3,4,5,6,7,8])); var mybind = a.output.myBind(b,[1,2,3,4,5,6,7,8]); console.log("===================================="); mybind(9); console.log("============== binb bindc======================"); console.log(a.output.myBind(b)()); console.log(a.output.myBind(b).myBind(c)());//有一定的包裹性obj._fn_还是那个函数 </script> </body> </html>
|
问题:a.output.myBind(b).myBind(c)结果是b
这里会有一个问题,a.output.myBind(b).myBind(c)()的结果是b,最初觉得很奇怪但是想了一下主要问题在于。bind是一个包裹性的函数,第一次bind之后函数内部的this是b而在绑定一次c之后执行的是obj_fn_这里面的this是b所以执行还是b。