JS实现 call 函数

文章介绍了JavaScript中call函数的作用,即改变this的指向,并通过代码示例展示了如何手动实现call函数的核心功能。在实现过程中,考虑了处理无上下文、函数参数及返回值的情况。最后,将此功能添加到函数的原型上,创建了myCall方法。
摘要由CSDN通过智能技术生成

参考蓝桥云课

在尝试去实现 call 函数之前,我们再来回顾一下它的用法,call 函数是为了改变 this 的指向,代码如下:

 var userName = "xxx";
const person = {
  userName: "zhangsan",
};

function fn() {
  console.log(this.userName);
}

fn.call(); // 直接调用,this 指向 window,输出 'xxx'
fn.call(person); // 用 call,this 指向 person,输出 'zhangsan'

call 是写到 Function.prototype 上的方法,而本节我们要实现的 myCall 是把函数当作参数传递进去,两者只是调用形式不同,原理都是一样的。

我们尝试来实现一下显式改变 this 指向的功能,调用对象中的函数,this 指向为这个对象,所以我们需要做的操作是:

  • 把函数 fn 挂载到要指向的对象 context 上。
  • 执行 context.fn,执行完了删除 context 上的 fn 函数,避免对传入对象的属性造成污染。

代码实现如下:

function myCall(fn, context) {
  // 把函数 fn 挂载到对象 context 上。
  context.fn = fn;

  // 执行 context.fn
  context.fn();

  // 执行完了删除 context 上的 fn 函数,避免对传入对象的属性造成污染。
  delete context.fn;
}

测试一下:

var userName = "xxx";
const person = {
  userName: "zhangsan",
};

function fn() {
  return this.userName;
}

myCall(fn, person); // 输出 'zhangsan'
myCall(fn, window); // 输出 'xxx'

可以看到,仅仅三行代码,我们就实现了 call 函数的核心功能。

不过这里面有一些其他细节需要处理,比如:

  • 要处理 context 不传值的情况,传一个默认值 window。
  • 处理函数 fn 的参数,执行 fn 函数时把参数携带进去。
  • 获取执行函数 fn 产生的返回值,最终返回这个返回值。
    最终实现代码如下:
// 要处理 context 不传值的情况,传一个默认值 window。
function myCall(fn, context = window) {
  context.fn = fn;

  // 处理函数 fn 的参数,执行 fn 函数时把参数携带进去。
  const args = [...arguments].slice(2);

  // 获取执行函数 fn 产生的返回值。
  const res = context.fn(...args);
  delete context.fn;

  // 最终返回这个返回值
  return res;
}

测试一下:

const obj = {
  count: 10,
};

function fn(x, y, z) {
  console.log(this.count + x + y + z);
}

myCall(fn, obj, 1, 2, 3); // 执行函数 fn,输出 16

这样我们就实现了 call 函数该有的功能,原生的 call 函数是写到 Function.prototype 上的方法,我们也尝试在函数的原型上实现一个 myCall 函数,只需稍加改造即可,代码实现如下:

// 写到函数的原型上,就不需要把要执行的函数当作参数传递进去
Function.prototype.myCall = function (context = window) {
  // 这里的 this 就是这个要执行的函数
  context.fn = this;
  // 参数少了一个,slice(2) 改为 slice(1)
  const args = [...arguments].slice(1);
  const res = context.fn(...args);
  delete context.fn;
  return res;
};

测试一下:

const obj = {
  count: 10,
};

function fn(x, y, z) {
  console.log(this.count + x + y + z);
}

fn.myCall(obj, 1, 2, 3); // 执行函数 fn,输出 16
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值