call()的实现

214 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情

前言

之前写过一篇关于this指向的问题,其中提到了可以通过call(),apply(),bind()三种方法改变this的指向,有兴趣的可以点击去看看,这篇文章来写一下call(),apply(),bind()的实现。

call()

首先要明确call的参数是什么,都是什么意义。

  • call的第一个参数是将来调用者this的指向
  • 剩下的参数作为实参传递给调用者

要实现第一条我们只要把第一参数设置为对象的属性就行了,那么代码就可以这样实现

Function.prototype.myCall = function(context){
     context.fn = this;
     context.fn();
     delete context.fn;
}

这里可以测试一下,

animal={color:'yellow'}
function dog(){
    console.log(this.color)
}
dog.myCall(animal) //这里的打印结果就会是yellow,这就实现了call的第一个功能,改变this的指向

接着来实现第二部分,也就是把剩余的参数当做实参传递给函数执行者

在这里我们要知道一个知识点,那就是arguments可以去到所有的实参,这里我们模仿call的特性,取出其中的第二个到最后一个,然后放到数组中。

animal={color:'yellow'}
function dog(age,name){
    console.log(arguments)
    console.log(this.color)
    console.log(age)
    console.log(name)
}
dog(6,'小白')

上面代码打印的arguments如下图:

image.png

既然已经拿到了所有的参数,那我们就可以实现第二部分内容了,最终代码如下

Function.prototype.myCall = function(context){
     context.fn = this;
    var args = [];
    for(var i = 1, len = arguments.length; i < len; i++) {
        args.push('arguments[' + i + ']');
    }
      eval('context.fn(' + args +')');
     delete context.fn;
}

在试一下,如下图

image.png 可以看到,this的指向也改变了,参数也都传递成功了,这里已经差不多可以算是成功了,但是还有一个钟情况就是this可能传递的是null,也就是说不传递参数的时候,那这时候其实就是使用的window,这时候就要对代码进行最后一步的调整了,如下

Function.prototype.myCall = function(context){
    var context = context || window;
     context.fn = this; //通过this来获取调用myCall的函数
    var args = [];
    for(var i = 1, len = arguments.length; i < len; i++) {
        args.push('arguments[' + i + ']');
    }
      eval('context.fn(' + args +')');
     delete context.fn;
}

这时候就很完美了

上述代码中的push实参和把剩余参数从数组变成参数的方法也可以写成下面这种方式

Function.prototype.myCall = function(context){
            context = context || window
            context.fn= this
            var args = []
            for(var i=1;i<arguments.length;i++){
                args.push(arguments[i])
            }
            var result = context.fn(...args)
            delete context.fn
            return result
        }

总结

call()的实现大概就是这样,完结,撒花