JavaScript Guidebook

JavaScript 完全知识体系

Function.prototype.call

Function.prototype.call 方法用于指定函数调用指向的 this 指针,并分别提供参数作为指定函数的参数。

语法

语法:

call(thisArg: any, ...argArray: any[]): any;

参数

参数说明类型
thisArg可选参数。调用函数时指向的 this 指针。
args可选参数。调用函数参数列表。

示例

function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
Product.call(this, name, price);
this.category = 'food';
}
function Toy(name, price) {
Product.call(this, name, price);
this.category = 'toy';
}
const cheese = new Food('cheese', 5);
const robot = new Toy('robot', 40);
console.log(cheese);
// {
// category: "food",
// name: "cheese",
// price: 5,
// }
console.log(robot);
// {
// category: "toy",
// name: "robot",
// price: 40,
// }

兼容实现

实现步骤:

  1. 确保调用 call 方法的调用方为 function 类型
  2. 参数:将参数数组转化为数组形式 ❗️(重点)
  3. 执行上下文:确保 context 执行上下文,用 window 全局变量兜底
  4. this(调用方函数)赋值到执行上下文上,用 Symbol 创建属性键名以防冲突
  5. 执行调用方函数,并保存调用结果 ❗️(重点)
  6. 删除调用方(执行上下文)的键值对
  7. 返回结果
Function.prototype.call = function (context) {
// context 是调用 call 的时候参数中的第一个参数
// 先判断当前的调用方是不是一个函数
if (typeof this !== 'function') {
throw new TypeError(`${this}.call is not a function.`);
}
// 保存调用方给的参数
const args = [...arguments].slice(1);
// 确定执行方的类型,因为可以传 null 和 undefined
context = context || window;
// 将调用方的内容保存为执行方的一个属性,为了保证不与执行方中的 key 键名重复
const fn = Symbol('fn');
context[fn] = this;
// 执行保存的函数,这个时候作用域就是在调用方的对象的作用域下执行,改变 this 的指向
const result = context[fn](...args);
// 执行完删除刚才新增的属性值
delete context[fn];
// 返回执行结果
return result;
};

由于 callapply 的区别就在于传参的方式不同:

fn.call(ctx, arg1, arg2, arg3);
fn.call(ctx, [arg1, arg2, arg3]);
  • call 调用函数的参数是散列的形式
  • apply 调用函数的参数是数组的形式