js深入之call/apply/bind的模拟实现

前言
call,apply,bind这三个方法都是用来改变函数的this指向

call
call() 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。

模拟实现 
基本思想是把fn.call(obj,args)中的fn赋值为obj的属性

然后调用obj.fn即可实现fn中this指向的改变
 

   // call和apply实现方式类似,只是传参的区别
    //myCall函数的参数,没有传参默认是指向window
    Function.prototype.myCall = function (context = window) {
        context.fn = this //为对象添加方法(this指向调用myCall的函数)
        let args = [...arguments].slice(1) // 剩余的参数
        let res = context.fn(...args)  // 调用该方法,该方法this指向context
        delete context.fn //删除添加的方法
        return res
    }

测试

    var foo = {
        value: 'bind'
    };
    function demo(...rest) {
        console.log(this.value);
        console.log('hello')
        console.log(rest);
    }
    demo.myCall(foo, 'bind1')


apply 
call和apply的功能相同,区别是传递函数参数的方式不同,call是一个一个传入,apply是通过一个数组传递 

模拟实现  
    Function.prototype.myApply = function (context = window) {
        context.fn = this;
        let args = arguments[1] // 剩余的参数
        let res = context.fn(...args);
        delete context.fn;
        return res;

    }
测试

    var foo = {
        value: 'bind'
    };
    function demo(...rest) {
        console.log(this.value);
        console.log('hello')
        console.log(rest);
    }
    demo.myApply(foo, ['bind1'])


bind 
bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。

 bind的几个特性如下 :

返回一个新的函数
分段接收参数
改变this指向
返回的新函数可以使用new操作符

 arguments
想要实现模拟的话,我们还需要了解一下arguments对象。

arguments对象不是一个Array。它类似于Array,但除了length属性和索引元素之外没有任何Array属性。可将arguments转换为:

// es5
var args = Array.prototype.slice.call(arguments);
var args = [].slice.call(arguments);
 
// es6
const args = Array.from(arguments);
const args = [...arguments];

模拟实现
    Function.prototype.myBind = function (context) {
        var self = this; // this 指向调用者
        var args = Array.prototype.slice.call(arguments, 1); //第二个参数
        var fNOP = function () { };
        var fBound = function () { //返回一个函数
            var bindArgs = Array.prototype.slice.call(arguments);//接受的参数
            // console.log(bindArgs);
            return self.apply(context, args.concat(bindArgs));
        }
        //当 bind 返回的函数作为构造函数的时候
        fNOP.prototype = this.prototype;
        fBound.prototype = new fNOP();
        return fBound;
    }

测试 

    var foo = {
        value: 'bind'
    };
    function demo(...rest) {
        console.log(this.value);
        console.log('hello')
        console.log(rest);
    }
    demo.prototype.friend = 'prop';
    let demos = demo.myBind(foo, 'bind1')
    let bar = new demos(35);
    console.log(bar.friend);

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值