Skip to content

手写call

约 458 字大约 2 分钟

2025-06-03

什么是 call 方法

在 JavaScript 中,call()  是一个内置的函数方法,它允许你在特定的作用域中调用函数,即可以改变函数执行时的  this  指向。

基本语法:

func.call(thisArg, arg1, arg2, ...)

原生 call 方法示例

const person = {
  name: "ling_wu",
};

function getName() {
  console.log(this.name);
}

// 使用call改变this指向
getName.call(person); //输出:"ling_wu"

这个过程实际上的操作是 person 这个对象中创建了一个 getName 的函数,并且这个函数的 this 指向了 person 这个对象

person = {
  name: "ling_wu",
  getName: function () {
    console.log(this.name);
  },
};

getName 执行完成后再从 person 对象中删除 getName 这个属性

手动实现 call 方法

有了上面的初步分析我们来初步实现

第一步:基本实现

Function.prototype.myCall = function (context) {
  // getName.myCall(person)这个位置getName调用的myCall,所以this指向getName
  context.fn = this;
  const result = context.fn();
  delete context.fn;
  return result;
};

第二步:考虑参数

call 是可以传递参数的,并且是都喊分隔,可以使用 es6 的...args 来接收

Function.prototype.myCall = function (context, ...args) {
  context.fn = this;
  const result = context.fn(...args);
  delete context.fn;
  return result;
};

第三步:对传入 null 做处理

call 函数中如果传入的是 null 则默认指向全局对象(MDN 中 call 函数是这样描述的),所以给 context 赋值一个默认值

Function.prototype.myCall = function (context, ...args) {
  context = context || window;
  context.fn = this;
  const result = context.fn(...args);
  delete context.fn;
  return result;
};

第四步:对 fn 属性名做唯一处理,怕属性名冲突

Function.prototype.myCall = function (context, ...args) {
  context = context || window;
  const fn = Symbol("fn");
  context[fn] = this;
  const result = context[fn](...args);
  delete context[fn];
  return result;
};

使用示例

const person = {
  name: "ling_wu",
};

function getName(age, sex) {
  console.log(`name:${this.name},age:${age},sex:${sex}`);
}

//使用原生的call
getName.call(person, 26, ""); //输出:name:ling_wu,age:26,sex:男

//使用我们自己实现的myCall
getName.myCall(person, 26, ""); //输出:name:ling_wu,age:26,sex:男