JS 手写call、apply和bind方法

news2025/2/27 20:58:26

手写call、apply和bind方法

  • 一、方法介绍
    • 1.1 call 方法
    • 1.2 apply 方法
    • 1.3 bind
  • 二、方法的实现
    • 2.1 call 方法
    • 2.2 apply 方法
    • 2.3 bind 方法

一、方法介绍

apply、call和bind都是系统提供给我们的内置方法,每个函数都可以使用这三种方法,是因为apply、call和bind都实现在了Function的原型上(Function.prototype),而他们的作用都是给我们函数调用时显式绑定上this。下面先介绍一下它们的基本用法:

1.1 call 方法

call方法:使用一个指定的 this值和单独给出的一个或多个参数来调用一个函数。

  • 使用语法:func.call(thisArg, arg1, arg2, …)
    • thisArg:在func函数调用时绑定的this值;
    • arg1, arg2, …:指定的参数列表,将作为参数传递给func函数;
  • 使用效果:
function foo(x, y ,z) {
  console.log(this, x, y, z)
}

const obj = { name: 'curry', age: 30 }
/**
 * 1.将obj对象绑定给foo函数的this
 * 2.call剩余参数中的a b c分别传递给foo函数对应的三个参数
 */
foo.call(obj, 'a', 'b', 'c')

在这里插入图片描述

1.2 apply 方法

apply方法:调用一个具有给定this值的函数,以及以一个**数组(或类数组对象)**的形式提供的参数。

  • 使用语法:func.apply(thisArg, [argsArray])
    • thisArg:在func函数调用时绑定的this值;
    • [argsArray]:一个数组或者类数组对象,其中的数组元素将作为单独的参数传给func函数;
  • 使用效果:
function foo(x, y ,z) {
  console.log(this, x, y, z)
}

const obj = { name: 'curry', age: 30 }
/**
 * 1.将obj对象绑定给foo函数的this
 * 2.数组中的1 2 3分别传递给foo函数对应的三个参数
 */
foo.apply(obj, [1, 2, 3])

在这里插入图片描述

1.3 bind

bind方法:创建一个新的函数,在bind()被调用时,这个新函数的this被指定为bind()的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

  • 使用语法:func.bind(thisArg[, arg1[, arg2[, …]]])
    • thisArg:调用func函数时作为this参数传递给目标函数的值;
    • arg1, arg2, …:当目标函数被调用时,被预置入func函数的参数列表中的参数;
  • 使用效果:
function foo(...args) {
  console.log(this, ...args)
}

const obj = { name: 'curry', age: 30 }
/**
 * 1.将obj对象绑定给foo函数的this
 * 2.bind剩余参数中的1 2 3分别传递给foo函数中参数
 * 3.也可在newFoo调用时传入参数,这时bind传递的参数会与newFoo调用时传递的参数进行合并
 */
const newFoo = foo.bind(obj, 1, 2, 3)
newFoo()
newFoo('a', 'b', 'c')

在这里插入图片描述

二、方法的实现

function foo(...arg) {
  console.log(this.name, ...arg);
}

function obj() {
  this.name = 'obj'
}

2.1 call 方法

Function.prototype.myCall = function(context, ...args) {
  // 1. 检查上下文是否为 null 或 undefined,如果是则设置为全局对象(浏览器中为 window)
  context = context || window;

  // 2. 为上下文对象创建一个唯一属性来保存当前函数,
  // 以便在调用完后删除这个属性,避免污染原始对象
  const fnKey = Symbol();
  context[fnKey] = this;

  // 3. 通过上下文对象调用函数并传入参数
  const result = context[fnKey](...args);

  // 4. 删除添加的属性
  delete context[fnKey];

  // 返回函数调用结果
  return result;
};

// 原始call方法
foo.call(obj, 1, 2, 3)
// 手写call方法
foo.myCall(obj, 1, 2, 3)

输出结果:
在这里插入图片描述

2.2 apply 方法

Function.prototype.myApply = function (context, args) {
  // 1.检查上下文是否为 null 或 undefined,如果是则设置为全局对象(浏览器中为 window)
  context = context || window;

  // 2. 为上下文对象创建一个唯一属性来保存当前函数,
  // 以便在调用完后删除这个属性,避免污染原始对象
  const fnKey = Symbol();
  context[fnKey] = this;

  let result;
  // 3. 检查是否传入了参数
  if (args) {
    // 使用扩展运算符展开参数数组,并通过上下文对象调用函数
    result = context[fnKey](...args);
  } else {
    // 如果未传入参数则直接通过上下文对象调用函数
    result = context[fnKey]();
  }

  // 4. 删除添加的属性
  delete context[fnKey];

  // 返回函数调用结果
  return result;
};

foo.apply(obj, [1, 2, 3])
foo.myApply(obj, [1, 2, 3])

输出结果:
在这里插入图片描述

2.3 bind 方法

Function.prototype.myBind = function(context, ...args) {
  const fn = this;

  return function(...innerArgs) {
    // 使用 apply 方法将传入的上下文和参数传递给函数,并返回调用结果
    return fn.apply(context, [...args, ...innerArgs]);
  };
};
let fn = foo.bind(obj,1,2,3)
let fn2 = foo.myBind(obj,1,2,3)
fn('a','b','c')
fn2('a','b','c')

输出结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1030564.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity中关于多线程的一些事

一.线程中不允许调用unity组件api 解决方法:可以使用bool值变化并且在update中监测bool值变化来调用关于unity组件的API. 二.打印并且将信息输出到list列表中 多线程可能同时输出多条信息。输出字符串可以放入Queue队列中。队列可以被多线程插入。 三.启用socke…

计算机基础协议/概念:推送数据— —WebSocket与SSE;前端Blob/URL下载文件

计算机基础协议/概念:推送数据— —WebSocket与SSE 1 WebSocket:双向通信 1.1 概念:通信过程 ①Upgrade:浏览器告知服务器升级为WebSocket协议 ②Switch:服务器升级成功后会返回101状态码 ③Communicate&#xff1…

SQL注入脚本编写

文章目录 布尔盲注脚本延时注入脚本 安装xampp,在conf目录下修改它的http配置文件,如下,找到配置文件: 修改配置文件中的默认主页,让xampp能访问phpstudy的www目录,因为xampp的响应速度比phpstudy快得多&am…

使用EasyExcel后端导出excel

官方文档:关于Easyexcel | Easy Excel 这里进行简单记录,方便确定是不是适用此方式: 零:实体类中注解用法 一:读excel /*** 强制读取第三个 这里不建议 index 和 name 同时用,要么一个对象只用index&…

代码随想录算法训练营第二天(C) | 977.有序数组的平方 209.长度最小的子数组 59.螺旋矩阵

文章目录 前言一、977.有序数组的平方二、209.长度最小的子数组三、59.螺旋矩阵总结 前言 java版: 代码随想录算法训练营第二天 | 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵_愚者__的博客-CSDN博客 一、977.有序数组的平方 …

Python环境配置及基础用法Pycharm库安装与背景设置及避免Venv文件夹

目录 一、Python环境部署及简单使用 1、Python下载安装 2、环境变量配置 3、检查是否安装成功 4、Python的两种模式(编辑模式&交互模式) 二、Pycharm库安装与背景设置 1、Python库安装 2、Pycharm自定义背景 三、如何避免Venv文件夹 一、P…

【Java 基础篇】Java TCP通信详解

TCP(Transmission Control Protocol)是一种面向连接的、可靠的网络传输协议,它提供了端到端的数据传输和可靠性保证。TCP通信适用于对数据传输的可靠性和完整性要求较高的场景,如文件传输、网页浏览等。本文将详细介绍Java中如何使…

搜索二叉树【C++】

文章目录 二叉搜索树二叉搜索树的模拟实现构造函数拷贝构造函数赋值运算符重载函数析构函数Insert循环递归 Erase循环递归 Find循环递归 二叉搜索树的应用K模型KV模型 完整代码普通版本递归版本 二叉搜索树 二叉搜索树又称为二叉排序树,它或者是一棵空树&#xff0…

Spring Security 的身份验证绕过漏洞CVE-2023-34035

文章目录 0.前言漏洞漏洞介绍描述 1.参考文档2.基础介绍2.1 组件简介:2.2 漏洞简介: 3.解决方案3.1. 升级版本 0.前言 背景:公司收到关于 Spring Security 的一个身份验证绕过漏洞的通知,该漏洞被标识为 CVE-2023-34035 漏洞 高 …

滴滴可观测平台 Metrics 指标实时计算如何实现了又准又省?

在滴滴,可观测平台的 Metrics 数据有一些实时计算的需求,承载这些实时计算需求的是一套又一套的 Flink 任务。之所以会有多套 Flink 任务,是因为每个服务按照其业务观测需要不同的指标计算,也就对应了不同数据处理拓扑。我们尽力抽…

ruoyi-vue-pro yudao 项目商城 mall 模块启用及相关SQL脚本

目前ruoyi-vue-pro 项目虽然开源,但是商城 mall 模块被屏蔽了,查看文档却要收费 199元(知识星球),价格有点太高了吧。 分享下如何启用 mall 模块,顺便贴上sql相关脚本。 一、启用模块 修改根目录 pom.xm…

时序预测 | MATLAB实现POA-CNN-GRU鹈鹕算法优化卷积门控循环单元时间序列预测

时序预测 | MATLAB实现POA-CNN-GRU鹈鹕算法优化卷积门控循环单元时间序列预测 目录 时序预测 | MATLAB实现POA-CNN-GRU鹈鹕算法优化卷积门控循环单元时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现POA-CNN-GRU鹈鹕算法优化卷积门控循环单元时间序…

工具篇 | Gradle入门与使用指南

介绍 1.1 什么是Gradle? Gradle是一个开源构建自动化工具,专为大型项目设计。它基于DSL(领域特定语言)编写,该语言是用Groovy编写的,使得构建脚本更加简洁和强大。Gradle不仅可以构建Java应用程序&#x…

亚马逊攀岩绳ASTM F2116 测试报告 EN892测试办理

攀岩绳是与攀岩安全带和锚点相连的一种装备,用于保护攀岩者,使其不会从高处跌落。攀岩绳由承重内芯和围绕内芯编织的护套组成。 亚马逊关于攀岩绳的政策 根据亚马逊的要求,所有攀岩绳均应经过检测,并且符合下列特定法规或标准要求…

使用GSAP创建惊艳的动画效果(一)

目录 GSAP简介GSAP的语法方法目标变量transform(变换)其它属性 vue中使用GSAP安装GSAP引用GSAP使用GSAP GSAP简介 GSAP是一个非常流行的js动画库,被广泛用于创建跨浏览器和跨平台的高性能动画。它的主要特点包括: 提供丰富的属性和方法,可用…

vue2中年份季度选择器(需要安装element)

调用 <!--父组件调用--><QuarterCom v-model"quart" clearable default-current/> 组件代码 <template><div><span style"margin-right: 10px">{{ label }}</span><markstyle"position:fixed;top:0;bottom:0…

人工智能安全-2-非平衡数据处理(2)

5 算法层面 代价敏感&#xff1a;设置损失函数的权重&#xff0c;使得少数类判别错误的损失大于多数类判别错误的损失&#xff1b; 单类分类器方法&#xff1a;仅对少数类进行训练&#xff0c;例如运用SVM算法&#xff1b; 集成学习方法&#xff1a;即多个分类器&#xff0c;然…

【Java 基础篇】Java网络编程实时数据流处理

在现代计算机应用程序中&#xff0c;处理实时数据流是一项关键任务。这种数据流可以是来自传感器、网络、文件或其他源头的数据&#xff0c;需要即时处理并做出相应的决策。Java提供了强大的网络编程工具和库&#xff0c;可以用于处理实时数据流。本文将详细介绍如何使用Java进…

Android之AMessage机制存/取原理(四十四)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注:Android…

从零学习开发一个RISC-V操作系统(三)丨嵌入式操作系统开发的常用概念和工具

本篇文章的内容 一、嵌入式操作习系统开发的常用概念和工具1.1 本地编译和交叉编译1.2 调试器GDB&#xff08;The GNU Project Debugger&#xff09;1.3 QEMU模拟器1.4 项目构造工具Make 本系列是博主参考B站课程学习开发一个RISC-V的操作系统的学习笔记&#xff0c;计划从RISC…