1、call的用法:
// 用法:Fn.call(this, param1, ......);
// Fn.call():当前实例(函数Fn),通过原型链的查找机制,找到Function.prototype上的call方法
//(function call () { [native code] });然后把call方法执行;
/**
call方法执行的内部机制:
(1)首先把要操作的函数中的this关键字的指向指向call方法第一个传递的实参值;
(2)把call方法传递的第二个及以后的参数获取到;
(3)把要操作的函数执行,并且把第二个以后的参数传递给这个执行的函数;
*/
2、模拟call方法的内部实现:
~function () {
/**
*
* @param {*} context : call的第一个参数,将调用call方法的函数中的this
* 指向context
*/
function call(context) {
// 如果未给call方法传递this指向的函数,默认指向window
context = context || window
let argus = [],
result;
// 参数的第二项才是函数的参数
for (let i = 1; i < arguments.length; i++) {
argus.push(arguments[i]);
}
context.$fn = this;
result = context.$fn(...argus);
delete context.$fn;
}
// 扩展到内置类的原型上
Function.prototype.call = call;
}()
3、call方法的应用:
function fn1 () { console.log(1); }
function fn2 () { console.log(2); }
fn1.call(fn2); // 1
fn1.call.call(fn2); // 2
Function.prototype.call(fn1);
Function.prototype.call.call(fn1);
// 解析
/** 1、
fn1.call(fn2);
执行call,先把call方法中的this改成 fn1,然后把 fn1中的this改成 fn2,但是fn1执行和this无关,
所以输出 1 ;
*/
/** 2、
fn1.call.call(fn2);
先把fn1.call看做一个整体,执行第二个call方法:
执行第二个call方法时,
第一步把call方法中的this改成了 fn1.call;
第二步把fn1.call中的this改成了fn2,也就是把call第一个call函数体中的this改成了fn2;
第三步执行fn1.call;
现在变成了执行 fn1.call(),此时fn1.call中的this也就是这个call方法中的this在上面已经被
修改成了fn2;所以是在执行 fn2,但是call又没传递参数,fn2中的this为undefined,单纯的执行fn2,
结果为 2
*/
/** 3、
Function.prototype.call(fn1);
执行call,把call中的this改成 Function.prototype,把Function.prototype中的this改成fn1;
Function.prototype是一个匿名函数,也是一个空函数,执行结果没有任何输出;
*/
/** 4、
Function.prototype.call.call(fn1);
执行第二个call,把call中的this修改为Function.prototype.call;
把 Function.prototype.call中的this修改成 fn1;
执行Function.prototype.call,就是在执行 fn1;
*/
/**
规律:函数1.call.call ...... .call(函数2),就是在执行 函数2;
函数1.call.call ...... (无论点多少个call)=== Function.prototype.call
*/
网友评论