JS中call和Apply原理分析研究

call和apply共同点

call和apply都是为了改变某个函数运行时内部this的指向,会立即调用该函数

call和apply不同点

call方法接收的是若干个参数的列表
apply方法接收的是一个包含多个参数的数组

call方法使用说明

let bar = {
   sex: "男"
};

function foo(age) {
   console.log(this,this.sex, age);
}

// foo(10)  //Window undefined 10
foo.call(bar, 10) //{sex: "男"} "男" 10

通过call方法调用foo函数,会立即执行foo函数,同时this会指向传递的第一个参数bar,第二个或后边的以参数的形式传递给foo函数

模拟call方法

let bar = {
    sex: "男"
};

function foo(age) {
    console.log(this.sex, age); //男 10
    console.log(this); //{sex: "男", fn: ƒ}
}

Function.prototype.myCall = function (context) {
    //第一种获取形参的方法
    // let arr = [];
    // for(let i=0; i

当调用foo函数时,如果属性或方法没有找到,会向原型链上查找,foo构造函数的__proto__指向的是Function.prototype对象,所以我们在模拟call方法时,可以给Function的原型添加方法。

foo调用myCall方法 等同于给bar添加一个fn属性,而fn属性又对应一个foo方法,然后就是调用fn方法。如:

 function bar(){
    this.sex = "男";
    this.fn = function foo(age) {
        console.log(this.sex, age);
    }
}

具体步骤是:

  1. 首先通过arguments拿到所所有的实际参数,再通过splice截取除了第一个参数的列表

  2. 把this对象(this是foo函数)赋值到bar对象的fn属性上,并执行fn函数

  3. 把先前处理好的参数传递过去,并获取返回结果(如果无就返回undefined),此时就相当于把bar对象中带this的属性和方法都添加到了foo对象中

  4. 删除bar的fn属性(只是删除fn属性,但this已经指向了传入的那个对象),并返回结果

    注意
    在foo函数中打印的this为什么还是有fn函数呢,我们已经通过delete context.fn; 把fn函数删除了啊?我个人理解:这里的显示是因为delete context.fn在打印之后执行的,而我们看到的是删除之前的数据,如果我们点开,里边显示的才是foo真正具有的属性(如下图),或者我们在delete context.fn之后再给context赋值一个属性,再次打印就看不到fn属性了
    在这里插入图片描述

apply方法使用说明

let bar = {
     sex: "男"
 };

 function foo(age) {
     console.log(this.sex, age); //男 10
 }

 foo.apply(bar, [10])

模拟apply方法

 let bar = {
     sex: "男"
 };

 function foo(age) {
     console.log(this.sex, age); //男 10
 }

 Function.prototype.myApply = function(context){
     //第一个参数content为调用call方法的函数内this的指向
     console.log(context);//{sex: "男"}
     console.log(this);//this是调用myCall的foo()函数
     //如果不传入参数,默认指向window
     context = context || window;
     //动态的将this赋值给content的fn属性
     context.fn = this;
     let result;
     //调用content的fn函数,并判断是否有第二个参数,如果有就传递过去
     if(arguments[1]) {
         result = context.fn(...arguments[1])
     } else {
         result = context.fn()
     }
     //删除fn属性
     delete context.fn;
     return result
 };

 foo.myApply(bar, [10]); //男 10

apply和call方法实现类似,只不过参数是以数组的形式传递

你可能感兴趣的:(前端)