面试题之手写call,apply,bind

news/2025/2/21 2:56:56

面试中,手写call,apply,bind是常见的题目,主要考察对JavaScript中函数上下文(this)和参数传递的理解。对于我这个小菜鸟来说,这无疑也是一道难题呢,嘤嘤嘤


1. 手写 call

call 方法允许你调用一个函数,并显式地指定函数内部的 this 值,同时可以逐个传递参数。

实现思路:

  1. 将目标函数绑定到指定的上下文对象(thisArg)。

  2. 调用目标函数。

  3. 返回目标函数的执行结果。

代码实现:

Function.prototype.myCall=function(thisArg,...args){
    if(typeof this!=='function'){
        //如果调用者不是一个函数,则抛出错误
        throw new TypeError("myCall must be called on a function");
    }

    thisArg = thisArg||(thisArg===null?globalThis:thisArg)
    thisArg['fn']=this    
    thisArg['fn'](...args)// 这里相当于立即执行函数
    delete thisArg['fn']

}

测试:

function greet(...message){
    console.log(`${message},my name is ${this.name}`)
}

const person = {name:'alita'}
greet.myCall(person,'hello','hi','嘻嘻')//hello,hi,嘻嘻,my name is alita


2. 手写 apply

apply 方法与 call 类似,但参数是以数组的形式传递的。

实现思路:

  1. 将目标函数绑定到指定的上下文对象(thisArg)。

  2. 调用目标函数。

  3. 返回目标函数的执行结果。

代码实现:

Function.prototype.myApply = function (thisArg, argsArray) {
  // 检查是否为函数
  if (typeof this !== "function") {
    throw new TypeError("myApply must be called on a function");
  }

  // 如果 thisArg 是 null 或 undefined,按照规范,this 应该指向全局对象
  thisArg = thisArg || (thisArg === null ? globalThis : Object(thisArg));

  // 将函数绑定到 thisArg 上
  const fn = Symbol("fn");
  thisArg[fn] = this;

  // 调用函数并获取结果
  const result = thisArg[fn](...argsArray);

  // 删除临时属性
  delete thisArg[fn];

  return result;
};

测试:

function greet(message) {
  console.log(`${message}, my name is ${this.name}`);
}

const person = { name: "Alice" };
greet.myApply(person, ["Hello"]); // 输出: Hello, my name is Alice


3. 手写 bind

bind 方法用于创建一个新的函数,并将该函数的 this 值永久绑定到指定的对象上。与 callapply 不同,bind 不会立即调用函数,而是返回一个新的函数。

实现思路:

  1. 创建一个新的函数。

  2. 将目标函数的 this 值绑定到指定对象。

  3. 支持预绑定参数。

  4. 支持作为构造函数使用(可选)。

代码实现:

Function.prototype.myBind = function (thisArg, ...bindArgs) {
  // 检查是否为函数
  if (typeof this !== "function") {
    throw new TypeError("myBind must be called on a function");
  }

  const fn = this;

  // 返回一个新的函数
  const boundFunction = function (...callArgs) {
    // 合并预绑定参数和调用时的参数
    const finalArgs = bindArgs.concat(callArgs);

    // 如果作为构造函数调用,this 指向新创建的对象
    if (new.target) {
      return new fn(...finalArgs);
    } else {
      // 否则,this 指向绑定的对象
      return fn.apply(thisArg, finalArgs);
    }
  };

  // 修复绑定函数的原型链
  boundFunction.prototype = Object.create(fn.prototype);

  return boundFunction;
};

测试:

function greet(message) {
  console.log(`${message}, my name is ${this.name}`);
}

const person = { name: "Alice" };
const greetAlice = greet.myBind(person, "Hello");
greetAlice(); // 输出: Hello, my name is Alice

// 测试作为构造函数
function Person(name, age) {
  this.name = name;
  this.age = age;
}

const createPerson = Person.myBind(null, "Alice");
const alice = new createPerson(25);
console.log(alice); // { name: "Alice", age: 25 }


总结

  1. callapply

    • 都用于立即调用函数并改变上下文。

    • 区别在于参数传递方式:call 是逐个传递,apply 是数组传递。

    • 实现时,主要通过临时属性绑定和调用目标函数。

  2. bind

    • 返回一个新的函数,this 值和参数被预绑定。

    • 支持延迟调用和作为构造函数使用。

    • 实现时需要处理 new 调用的情况,并修复原型链。

这些实现可以帮助你更好地理解 JavaScript 中的函数上下文和参数传递机制。


http://www.niftyadmin.cn/n/5860132.html

相关文章

《DeepSeek-V3:人工智能大语言模型》

《DeepSeek-V3:人工智能大语言模型》 1. 引言 我们介绍了 DeepSeek-V3,这是一个强大的专家混合 (MoE) 语言模型,总共有 671B 个参数,每个令牌激活了 37B。 为了实现高效的推理和具有成本效益的训练,DeepSeek-V3 采用了多头潜在注意力 (MLA) 和 DeepSeekMoE 架构,这些…

Spring Boot中API响应结构的最佳实践

在Spring Boot应用程序中,设计一个清晰、一致的API响应结构是确保代码可维护性和可扩展性的关键。本文将探讨如何在Spring Boot中构建最佳的API响应结构,以便于前端开发人员理解和使用,同时为后端开发人员提供灵活的扩展能力。 1. 标准化的响…

java网络编程02 - HTTP、HTTPS详解

HTTP、HTTPS详解 文章目录 HTTP、HTTPS详解一:HTTP超文本传输协议1:HTTP协议的工作流程2:URI和URL2.1:DNS域名解析 3:HTTP报文的组成结构3.1:请求报文3.2:响应报文3.3:HTTP报文字段3…

高德地图android sdk(备忘)

依赖 // 权限请求框架:https://github.com/getActivity/XXPermissions implementation com.github.getActivity:XXPermissions:20.0 // https://mvnrepository.com/artifact/com.amap.api/navi-3dmap-location-search implementation com.amap.api:navi-3dmap-loca…

当Qt遇见IOCP:用C++打造高并发服务器

一、为什么选择IOCP技术? 在Windows平台开发高并发网络服务时,许多开发者都会遇到这样的困境:当需要同时处理成千上万的客户端连接时,传统的select模型或普通线程池方案会遭遇性能瓶颈。这正是IOCP(Input/Output Comp…

从猜想终结到算法革新,弹性哈希开启数据存储新篇章

目录 哈希表的前世今生基本原理从传统到现代:哈希表的演变历程 安德鲁 克拉皮文及其团队的创作历程弹性哈希详解基本原理优点技术细节 漏斗哈希解析基本原理优点技术细节 新算法的实际应用案例电子商务推荐系统金融交易监控系统社交媒体内容过滤物联网设备管理 结论…

RT-Thread+STM32L475VET6实现红外遥控实验

文章目录 前言一、板载资源介绍二、具体步骤1. 确定红外接收头引脚编号2. 下载infrared软件包3. 配置infrared软件包4. 打开STM32CubeMX进行相关配置4.1 使用外部高速时钟,并修改时钟树4.2 打开定时器16(定时器根据自己需求调整)4.3 打开串口4.4 生成工程 5. 打开HW…

【数据分析】2.数据分析业务全流程

业务流程方法论:3阶段6步骤 一、课程核心内容结构 1. 方法论概述 目标:系统性地解决商业中的关键问题框架:分为三个阶段,每个阶段包含两个步骤适用场景:适用于数据分析师、业务经理等需要通过数据分析支持决策的从业…