js深入之call、apply和bind模拟实现

callapply
作用:调用一个对象的一个方法,以另一个对象替换当前对象。
区别:调用参数形式不同。(call参数依次给出,apply通过Array对象传入)
this:谁调用我,我就指向谁
首先看个调用call的栗子:

var foo = {
    value: 1
};

function fn() {
    console.log(this.value);
}

fn.call(foo); // 1

注意:
1、call改变了this的指向,指到foo
2、fn函数执行
即可将上面的代码改变成下面这种形式:

var foo = {
    value: 1,
    fn: function() {
        console.log(this.value)
    }
};

foo.fn(); // 1

即将fn作为对象foo的属性,然后进行调用。
则可总结出模拟实现的步骤:
1、将函数设置为对象的属性,注意该函数逇参数处理。
2、执行该函数;
3、删除该函数。
故call的模拟实现如下:

Function.prototype.myCall = function (context) {
    var context = context || window; //如果this参数传的是null,则此处指向window
    context.fn = this;    //获取调用myCall的函数,因为最后是函数调用myCall,this指向该函数,故this可获取

    var args = [];  //用来接收函数的参数
    for(var i = 1, len = arguments.length; i < len; i++) {
        args.push('arguments[' + i + ']');
    }//函数的参数第一个是this的指向,第二个以后才是自己的参数,故从1开始循环存入参数
    var result = eval('context.fn(' + args +')');//args可自动调用Array.toString()方法
    delete context.fn;
    return result; //函数的返回值
}

apply的实现跟call类似,只是后面的参数为一个数组,实现方法如下:

Function.prototype.myApply = function (context, arr) {
    var context = Object(context) || window;
    context.fn = this;
    var result;
    if (!arr) {    //如果函数没有其他参数
        result = context.fn();
    }
    else {
        var args = [];   //此处直接获取传入的数组的值
        for (var i = 0, len = arr.length; i  len; i++) {
            args.push('arr[' + i + ']');
        }
        result = eval('context.fn(' + args + ')')
    }
    delete context.fn;
    return result;
}

bind:bind() 方法会创建一个新函数。
当这个新函数被调用时,bind()的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。
特点
1. 返回一个函数
2. 可以传入参数
根据这两个特点可模拟如下:

Function.prototype.bind2 = function (context) {
    if (typeof this !== "function") {
      throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
    }    //如果调用bind的不是函数则报错

    var self = this;    //self指调用该方法的函数

    var args = Array.prototype.slice.call(arguments, 1);//获取bind2函数从第二个参数到最后一个参数

    var fNOP = function () {};
    //用一个空函数作为中转,将fbound.prototype = this.prototype

    var fbound = function () {
        self.apply(this instanceof self ? this : context,args.concat(Array.prototype.slice.call(arguments)));
    }
    //当作为构造函数时,this指向实例,self指向绑定函数,当结果为true时,this指向实例
    //当作为普通函数时,this指向window,self指向绑定函数,当结果为false时,this指向绑定的context

    fNOP.prototype = this.prototype;
    fbound.prototype = new fNOP();
    //修改返回函数的prototype为绑定函数的prototype,实例就可以继承函数原型中的值
    return fbound;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值