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 -> 100
把val插入到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是谁,最终就把谁执行
技巧:
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