JS 的apply call bind的实现
思路
三个函数简介
apply(this,[arg1,arg2…]);
call(this,arg1,arg2);
call和apply相似目的都是为了将执行函数的this值改变,后面的参数是为了填入参数
bind(this,arg1,arg2,arg3);
bind的主要目的是返回一个绑定了this的新的函数,后面的参数是填充进去的参数作为默认参数。
下面给一个阮一峰老师的例子:
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直接运算函数。返回函数的时候使用一个闭包
代码
<!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。