apply&call&bind比较以及源码实现

apply() & call() & bind() 异同

同:用于改变函数中this 的指向

异:apply()和call()使用传参不同;apply()和call()可以实现函数调用,而bind()不能

function fn(a, b) {
    console.log(this);
    console.log(a, b);
}
var obj = {
    a: 10
}
//fn.call(obj,1,2);
// apply()
//fn.apply(obj,[1,2]);

// bind()可以改变函数中this指向 但它不会调用函数
// 返回由指定this值和初始化参数改造的原函数拷贝,原函数不受影响
var newFn = fn.bind(obj, 1, 3);
newFn();

//apply()第二种使用场景
var arr = [10, 12, 45, 38];
var max = Math.max.apply(null, arr);
console.log(max);

bind()案例:

<body>
    <button id='btn'>接受验证码</button>
    <script>
        var btn = document.querySelector('#btn');
        var num = 10;
        btn.onclick = function() {
            //var that = this;
            this.innerHTML = '剩余时间'+num + "s";
            setInterval(function() {
                num--;
                this.innerHTML = '剩余时间'+num + "s";
            }.bind(this),1000);
        }
    </script>
</body>

手写bind

// 1 函数可以在bind的时候传递一部分参数,在执行函数的时候又传递一部分参数
// 2 当 bind 返回的函数作为构造函数的时候,bind 时指定的 this 值会失效,但传入的参数依然生效
Function.prototype.bind1 = function (othis) {
    if (typeof this !== 'function') {
        throw new TypeError('bind function error');
    }
    var args = Array.prototype.slice.call(arguments, 1), // 获取bind函数从第二个参数到最后一个参数,即为传递的参数
        _this = this;
    // return function () {
    //     return _this.apply(othis || window, args.concat(Array.prototype.slice.call(arguments)));
    // }
    var bound = function() {
        var bindArgs = Array.prototype.slice.call(arguments);
        // 当作为构造函数时,this 指向实例,_this指向绑定函数,因为下面一句 `fbound.prototype = this.prototype;`,已经修改了 fbound.prototype 为 绑定函数的 prototype,此时结果为 true,当结果为 true 的时候,this 指向实例。
        // 当作为普通函数时,this 指向 window,_this指向绑定函数,此时结果为 false,当结果为 false 的时候,this 指向绑定的 context。
        _this.apply(this instanceof _this ? this : obj, args.concat(bindArgs))
    }
    // 修改返回函数的 prototype 为绑定函数的 prototype,实例就可以继承函数的原型中的值
    var Fn = function() {};
    Fn.prototype = this.prototype;
    bound.prototype = new Fn();
    return bound;
}

手写call

Function.prototype.call1 = function(obj) {
    var obj = obj || window;
    obj.fn= this;
    var args = [];
    for(var i=1, len=arguments.length; i<len; i++) {
        args.push(`arguments[${i}]`);
    }
    var result = eval(`obj.fn(${args})`)
    delete obj.fn;
    return result;
}

手写apply

Function.prototype.apply1 = function(obj, arr) {
    var obj = Object(obj) || window;
    obj.fn = this; // obj上新增一个function fn() {} 此函数就为调用apply的函数。  后续再调用
    var result;
    if(!arr) {
        result = obj.fn();
    } else {
        var args = [];
        for(var i=0, len=arr.length; i<len; i++) {
            args.push('arr[' + i + ']');
        }
        result = eval('obj.fn(' + args + ')')
    }
    delete obj.fn;
    return result;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值