doubleyong
管理员
管理员
  • 最后登录2025-12-02
  • 发帖数1198
  • 最爱沙发
  • 喜欢达人
  • 原创写手
  • 社区居民
  • 忠实会员
阅读:4969回复:0

[Javascript]关于 call() 的一道面试题

楼主#
更多 发布于:2021-02-07 10:50
面试题:

题目:
function fn1() {console.log(1);}
 function fn2() {console.log(2);}
   fn1.call(fn2);  
   fn1.call.call(fn2); 
   fn1.call.call.call.call(fn2); 
   fn2.call();
   Function.prototype.call(fn2); 
   Function.prototype.call.call.call(fn2); 
   Function.prototype.call.call.call(fn1); 
   //Array.prototype.call([1,2,3]); 
   // 所以这样调用会报 TypeError 错误,
   // Array.prototype.call is not a function


考点:call方法的了解

答案解析:
  • fn1.call(fn2);
    这样的调用方式大家应该比较熟悉。call()函数的第一个参数应该是对象,fn2是函数,在Js中函数的本质也是对象;所以就是在fn2对象上调用fn1方法(注意fn2上本来是没有fn1这个方法的,调用call时会给fn2临时添加一个属性,它的值就是fn1方法的地址),等同的效果就是直接执行fn1();
  • fn2.call();
  1. call()可以不传参,这时候默认的就是全局Global对象,web环境中全局Global对象就是window。这里假定是web环境,所以相当于fn1.call(window);
  2. fn1.call(window);这个比较简单啦,这就是call的普通用法,等价于window.fn1();,实际上就是调用fn1()函数。
  • Function.prototype.call(fn2);
    首先,Function的原型比较特殊,它的原型是匿名空函数,别的类型的原型对象都是对象。
    所以这行代码表示在fn2上调用匿名空函数,所以就不会输出内容。

  • Function.prototype.call.call.call(fn2);,实际上和 fn1.call.call(fn2) 类似
  1. 可以拆分一下,这样容易说明问题 (Function.prototype.call.call).call(fn2);, 我们把Function.prototype.call.call给扩了起来。
  2. 来看Function.prototype.call.call,可以理解为Function.prototype.call的call方法;Function.prototype.call本身也是一个函数,如果不重写实际上所有函数的call方法都是 Function原型中的call方法, 即 Function.prototype.call
    也可以说Function.prototype.callFunction.prototype.call.callFunction.prototype.call.call.call...都是等价的,即Function原型上的call方法。
  3. 这样 (Function.prototype.call.call).call(fn2); 就相当于在fn2对象(js中函数也是对象)上调用原型中的call方法,且没有传递参数;实际上就是fn2.call();
    4)fn2.call(); 我们观察下call函数中没传值,默认就是window对象,fn2.call(window);又等价于 window.fn2();。
扩展:


模拟call()函数实现

call()的内部原理是怎样的?我们来模拟一下call函数

function call(context = window, ...args) {
  // this -> 指向调用call的那个函数(记住call前面必须是函数在调用)
  // 实际上就是执行 this(...args);
  // 是哪个对象要执行这个this函数?答案是context
  // 所以先把这个函数赋值给context的一个属性
  // 然后调用context这个新属性,接收传入的参数
  context.$fn = this;
  // 模拟call要处理的问题
  let res = context.$fn(...args);
  delete context.$fn; // 移除我们私自添加的函数 $fn
  return res;
}

参考:https://blog.csdn.net/ahiai/article/details/105145776
知识需要管理,知识需要分享
游客


返回顶部

公众号

公众号