JS 的apply call bind的实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yatsov/article/details/79780027

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。

猜你喜欢

转载自blog.csdn.net/yatsov/article/details/79780027