十四(4)、函数中的call方法 ------ 2019-12-

2019-12-29  本文已影响0人  自己写了自己看

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
*/
上一篇 下一篇

猜你喜欢

热点阅读