call的内部原理&重写内置call

155 阅读2分钟

“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第10篇文章,点击查看活动详情

Call的内部原理

fn1基于__proto__找到Funtion.prototype.call方法,把call方法执行,在call方法内部执行的时候,帮助我们把fn1执行了,并且让fn1中的this变为obj,并且把10/20传递给fn1

 //Cal内部实现的方法
        Function.prototype.call=function call(context,...params){
            //this->fn1
            //context->obj
            //params-[10,20]
            // 具体做的事情,把this(fn1)执行,让它里面的this指向context(obj),并且把params([10,20]) 传递给函数
}
const fn1=function fn(){
  console.log(1);
 };
let obj={
}
fn1.call(obj,10,20);

\

任何方法都是如此

  • 例如arr.push(100)

    • arr首先基于__proto__找到Array.prototype.push方法
    • 把找到的push方法执行
    • 在push方法的内部,
Array.prototype.push=function(val){

 this -> arr

 val -> 100val插入到this的末尾

}

假设没有call方法,我们想让fn执行怎么办

// 假设没有call方法,我们想让fn执行,方法中的this是obj,再传递10/20
//   + 首先给obj设置一个属性,属性值是当前要执行的函数fn
//   + 直接基于成员访问的方式,就可以把函数执行,并且this就是obj
const fn = function fn(x, y) {
    console.log(this, x + y);
};
let obj = {
    name: 'obj'
};
obj.fn=fn;
obj.fn();
fn.call(obj,10,20)=>在下面👇

重写内置Call

Function.prototype.call = function call(context, ...params) {
    // this->fn 要执行的函数   context->obj 要改变的THIS   params->[10,20] 要传递的实参
  	// 必须保证context是个对象 原始值类型不能设置成员 执行的时候会报错
    if (context == null) context = window;//如果第一个参数不传或者NUll this默认更改为window
    let type = typeof context; //判断所属对象
    if (type !== "object" && type !== "function") {
        // 把传递的原始值类型变为对应的对象类型值
        context = Object(context);
    }
    let key = Symbol(),
        result;
    context[key] = this; //给context添加属性 但是不能随便加 万一context本身的属性名就是你写的 这样会被覆盖 所以用了唯一值
    result = context[key](...params);
    delete context[key]; // 用完记得把新加的属性删除掉
    return result;
};

call中this是谁,最终就把谁执行

技巧:

  • 一个call,让call前面的执行
  • 两个及以上call,让call后面的执行

练习

const fn1 = function fn1() {
    console.log(1);
};
const fn2 = function fn2() {
    console.log(2);
};
fn1.call(fn2); //把fn1执行了 
//=>找到call方法 此时call中的this是fn1, call方法中的this是谁 就是把谁执行
fn1.call.call.call(fn2); 
//“CALL方法”.call(fn2)  ->把“CALL方法”执行,让方法中的this是fn2 -> 相当于fn2执行了  
Function.prototype.call(fn2); //把Function.prototype执行,没有任何输出
Function.prototype.call.call.call(fn2); //“CALL方法”.call(fn2) -> 让“CALL方法”执行,让它中的this是fn2 -> 相当于fn2执行  2