JS Function.call深入

Function.call深入

var ary = [12, 23, 34]

ary.slice
ary这个实例通过原型链的查找机制找到Array.prototype上的slice方法

ary.slice() 让找的slice方法执行, 在执行slice方法的过程中, 才把ary数组进行了截取

Funciton.call用法

call方法:
首先让原型上的call方法执行, 在执行call方法的时候, 让fn方法中的this变为第一个参数值obj, 然后再把fn这个函数执行

call 的参数是直接放进去的,第二第三第 n 个参数全都用逗号分隔,直接放到后面

Function.prototype.call = function(){}

var obj = {name: 'lemon'}
function fn(){
    console.log(this);
}
fn();
obj.fn();
fn.call(obj);

-> window
->Uncaught TypeError: obj.fn is not a funciton
->{name: 'lemon'}

模拟一个call方法

  1. 让fn中的this关键字变为context的值 obj
  2. 让fn方法执行
Function.prototype.myCall = function (context, ...args) {
    context = context || window;
    context.__proto__.fn = this;
    const result = context.fn(...args);
    // 执行fn时上下文context已被修改,不是我们所期望的call 

    delete context.__proto__.fn;
    return result;
}
fn.myCall(obj)

一道练习题

function fn1(){
    console.log(1);
}
function fn2(){
    console.log(2);
}
fn1.call.call(fn2)

->2

先执行fn1.call.call(fn2)
通过fn1的原型链找到call函数
通过找到call函数的原型链找到call
执行call.call(fn2), -> 2

  1. 前面的一串 fn.call.call.call.call 并没有调用,只是获取对象的call属性,所以,这一串的结果是 Function.call 属性。
  2. 所以那一串 就是 Function.call.call(fn2);还可以解理为 fn3.call(fn2)。
  3. 根据call的原理(可参考上面的call模拟),在 fn3执行call,其实际是这样执行的 fn2.fn3()。
  4. 由于 fn3实际上就是 call 函数,所以, fn2.fn3() 等价于 fn2.call()。
  5. 所以,上面那一串代码的最终结果,就是调用 fn2,所以结果输出 22.

概括性总结:
不怎么理解的话也可以记住这个概括性诀窍:
碰到两个及两个以上的call都是让第一个参数执行,第一个参数必须是函数;
第二个参数是改变第一个参数中this;
第三个及第三个以后的参数作为实参传给第一个参数。

原文地址:https://www.cnblogs.com/xiaoxu-xmy/p/13645817.html