前端JavaScript篇之实现call、apply 及 bind 函数

news2024/11/20 20:33:20

目录

  • 实现call、apply 及 bind 函数
    • 1. 实现call函数
    • 2. 实现apply函数
    • 3. 实现bind函数


实现call、apply 及 bind 函数

call、apply和bind函数都是用于改变函数中this指向的方法。它们的作用都是使函数能够在不同的对象上下文中运行。call方法和apply方法的作用类似,都是立即执行一个函数,并改变函数中this指向。bind方法和call、apply方法的作用也类似,都是改变函数中this指向。不同之处在于bind方法不会立即执行函数,而是返回一个新的函数,需要再次调用才能执行。

1. 实现call函数

call函数是JavaScript中的一个方法,它的作用是改变函数中this的指向,并立即执行该函数。call函数的作用是改变函数中this的指向,并且可以传递多个参数给函数。call函数的语法如下:

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

其中,thisArg是指定的this值,arg1、arg2等是传递给函数的参数。如果需要传递多个参数,可以使用逗号分隔。

// 在全局作用域中定义自定义的myCall方法
Function.prototype.myCall = function (context) {
  // 判断调用对象
  if (typeof this !== 'function') {
    console.error('type error')
  }
  // 获取参数
  let args = [...arguments].slice(1),
    result = null
  // 判断 context 是否传入,如果未传入则设置为 window
  context = context || window
  // 将调用函数设为对象的方法
  context.fn = this
  // 调用函数
  result = context.fn(...args)
  // 将属性删除
  delete context.fn
  return result
}

这段代码实现了一个自定义的call函数,它的作用和JavaScript内置的call函数类似,都是用来改变函数中this的指向。具体实现步骤如下:

  1. 判断调用对象是否为函数,如果不是则抛出错误。
  2. 使用展开运算符和slice函数获取传递给call函数的参数。
  3. 判断context是否传入,如果未传入则默认为window对象。
  4. 将当前函数设为context对象的一个属性。
  5. 调用context对象上的属性,并传入参数。
  6. 将context对象上的属性删除。
  7. 返回调用结果。

需要注意的是,在使用自定义的call函数时,需要确保传入的第一个参数是需要改变this指向的对象,后面的参数会作为函数调用时的参数传入。同时,为了避免修改context对象,我们需要在调用函数后将context对象上的属性删除。

下面是一个使用自定义的call函数的例子:

// 定义一个对象
let person = {
  name: '张三'
}

// 定义一个函数
function sayHello(age) {
  console.log(`我叫${this.name},今年${age}岁。`)
}

// 调用自定义的call函数
sayHello.myCall(person, 18) // 输出:我叫张三,今年18岁。

请添加图片描述

在这个例子中,我们定义了一个名为person的对象和一个名为sayHello的函数。使用自定义的call函数,将person对象作为第一个参数传入,改变sayHello函数中this的指向。同时,将18作为第二个参数传入,作为函数调用时的参数。最终输出了一句话,说明函数调用成功。

总结:通过实现自定义的call函数,我们可以更好地理解call函数的工作原理。call函数的作用是改变函数中this的指向,并立即执行该函数。我们可以将当前函数作为对象的一个属性来调用,从而改变函数中this的指向,使用apply函数获取传递给call函数的参数,并将它们传递给当前函数。最后删除对象上的属性。

2. 实现apply函数

apply是JavaScript中的一个函数方法,用于改变函数中this的指向,并立即执行该函数。apply函数和call函数的作用类似,不同之处在于apply函数的第二个参数是一个数组,这个数组中的元素会被作为参数传递给函数。apply函数和call函数的作用是一样的,只是传递参数的方式不同。apply函数的语法如下:

function.apply(thisArg, [argsArray])

其中,thisArg是需要改变this指向的对象,argsArray是一个数组,它的元素会作为函数调用时的参数传入。如果不需要传递参数,则可以传入一个空数组。

Function.prototype.myBind = function (context) {
  // 判断调用对象是否为函数
  if (typeof this !== 'function') {
    throw new TypeError('Error')
  }
  // 获取参数
  var args = [...arguments].slice(1),
    fn = this
  return function Fn() {
    // 根据调用方式,传入不同绑定值
    return fn.apply(this instanceof Fn ? this : context, args.concat(...arguments))
  }
}

这段代码实现了一个自定义的myBind方法,用于改变函数中this的指向,并返回一个新的函数。myBind方法的作用和call、apply方法类似,不同之处在于它不会立即执行函数,而是返回一个新的函数,需要再次调用才能执行。

myBind方法的实现思路如下:

  1. 判断调用对象是否为函数,如果不是则抛出一个类型错误。
  2. 获取myBind方法传入的参数,其中第一个参数是需要改变this指向的对象,后面的参数是传递给函数的参数。
  3. 返回一个新的函数Fn,用于接收myBind方法调用时传入的参数。
  4. 在新的函数Fn中,根据调用方式,传入不同的绑定值,使用apply方法执行原函数fn,并将参数传递给原函数fn。
  5. 如果新函数Fn被当做构造函数使用,即通过new关键字调用,那么this指向新创建的对象,否则this指向myBind方法传入的第一个参数context。

下面是一个使用自定义的myBind方法的例子:

Function.prototype.myBind = function (context) {
  // 判断调用对象是否为函数
  if (typeof this !== 'function') {
    throw new TypeError('Error')
  }
  // 获取参数
  var args = [...arguments].slice(1),
    fn = this
  return function Fn() {
    // 根据调用方式,传入不同绑定值
    return fn.apply(this instanceof Fn ? this : context, args.concat(...arguments))
  }
}

// 定义一个对象
let person = {
  name: '张三'
}

// 定义一个函数
function sayHello(age) {
  console.log(`我叫${this.name},今年${age}岁。`)
}

// 使用自定义的myBind方法改变函数中this的指向,并返回一个新函数
let newFn = sayHello.myBind(person, 18)

// 调用新函数
newFn() // 输出:我叫张三,今年18岁。

请添加图片描述

在这个例子中,我们定义了一个名为person的对象和一个名为sayHello的函数。使用自定义的myBind方法,将person对象作为第一个参数传入,改变sayHello函数中this的指向。同时,将18作为第二个参数传入,作为函数调用时的参数。调用myBind方法返回一个新的函数newFn,然后调用新函数newFn,输出了一句话,说明函数调用成功。

需要注意的是,使用自定义的myBind方法时,如果第一个参数不是一个对象,会导致函数调用失败。另外,如果新函数Fn被当做构造函数使用,即通过new关键字调用,那么this指向新创建的对象,否则this指向myBind方法传入的第一个参数context。

总结:myBind方法是用于改变函数中this指向的方法,并返回一个新的函数。myBind方法的实现思路是先判断调用对象是否为函数,然后获取myBind方法传入的参数,返回一个新的函数Fn,使用apply方法执行原函数fn,并将参数传递给原函数fn。如果新函数Fn被当做构造函数使用,那么this指向新创建的对象,否则this指向myBind方法传入的第一个参数context。在使用自定义的myBind方法时,需要注意第一个参数必须是一个对象,否则会导致函数调用失败。

3. 实现bind函数

bind是JavaScript中的一个函数方法,用于改变函数中this的指向,并返回一个新的函数,新函数中的this指向被绑定的对象,并且可以传递多个参数给函数。不会立即执行原函数。bind函数和call、apply函数的作用类似,不同之处在于bind函数返回一个新的函数,不会立即执行原函数。

bind函数的语法如下:

function.bind(thisArg[, arg1[, arg2[, ...]]])

其中,thisArg是需要改变this指向的对象,arg1、arg2等是传递给函数的参数。如果不需要传递参数,则可以省略后面的参数。

Function.prototype.myBind = function (context) {
  // 判断调用对象是否为函数
  if (typeof this !== 'function') {
    throw new TypeError('Error')
  }
  // 获取参数
  var args = [...arguments].slice(1),
    fn = this
  return function Fn() {
    // 根据调用方式,传入不同绑定值
    return fn.apply(this instanceof Fn ? this : context, args.concat(...arguments))
  }
}

这段代码实现了一个自定义的myBind方法,用于改变函数中this的指向,并返回一个新的函数。myBind方法的作用和call、apply方法类似,不同之处在于它不会立即执行函数,而是返回一个新的函数,需要再次调用才能执行。

myBind方法的实现思路如下:

  1. 判断调用对象是否为函数,如果不是则抛出一个类型错误。
  2. 获取myBind方法传入的参数,其中第一个参数是需要改变this指向的对象,后面的参数是传递给函数的参数。
  3. 返回一个新的函数Fn,用于接收myBind方法调用时传入的参数。
  4. 在新的函数Fn中,根据调用方式,传入不同的绑定值,使用apply方法执行原函数fn,并将参数传递给原函数fn。
  5. 如果新函数Fn被当做构造函数使用,即通过new关键字调用,那么this指向新创建的对象,否则this指向myBind方法传入的第一个参数context。

下面是一个使用自定义的myBind方法的例子:

Function.prototype.myBind = function (context) {
  // 判断调用对象是否为函数
  if (typeof this !== 'function') {
    throw new TypeError('Error')
  }
  // 获取参数
  var args = [...arguments].slice(1),
    fn = this
  return function Fn() {
    // 根据调用方式,传入不同绑定值
    return fn.apply(this instanceof Fn ? this : context, args.concat(...arguments))
  }
}

// 定义一个对象
let person = {
  name: '张三'
}

// 定义一个函数
function sayHello(age) {
  console.log(`我叫${this.name},今年${age}岁。`)
}

// 使用自定义的myBind方法改变函数中this的指向,并返回一个新函数
let newFn = sayHello.myBind(person, 18)

// 调用新函数
newFn() // 输出:我叫张三,今年18岁。

在这个例子中,我们定义了一个名为person的对象和一个名为sayHello的函数。使用自定义的myBind方法,将person对象作为第一个参数传入,改变sayHello函数中this的指向。同时,将18作为第二个参数传入,作为函数调用时的参数。调用myBind方法返回一个新的函数newFn,然后调用新函数newFn,输出了一句话,说明函数调用成功。

需要注意的是,使用自定义的myBind方法时,如果第一个参数不是一个对象,会导致函数调用失败。另外,如果新函数Fn被当做构造函数使用,即通过new关键字调用,那么this指向新创建的对象,否则this指向myBind方法传入的第一个参数context。

总结:myBind方法是用于改变函数中this指向的方法,并返回一个新的函数。myBind方法的实现思路是先判断调用对象是否为函数,然后获取myBind方法传入的参数,返回一个新函数Fn,使用apply方法执行原函数fn,并将参数传递给原函数fn。如果新函数Fn被当做构造函数使用,那么this指向新创建的对象,否则this指向myBind方法传入的第一个参数context。在使用自定义的myBind方法时,需要注意第一个参数必须是一个对象,否则会导致函数调用失败。

总结:
call、apply和bind函数是JavaScript中用于改变函数中this指向的方法。它们的作用都是改变函数中的this指向,使函数能够在不同的对象上下文中运行。

call和apply方法的作用类似,都是立即执行一个函数,并改变函数中this指向。不同之处在于传递参数的方式不同,call方法是将参数一个一个地传递给函数,而apply方法是将参数作为一个数组传递给函数。

bind方法和call、apply方法的作用也类似,都是改变函数中this指向。不同之处在于bind方法不会立即执行函数,而是返回一个新的函数,需要再次调用才能执行。

持续学习总结记录中,回顾一下上面的内容:
call、apply和bind函数都是用于改变函数中this指向的方法。它们的作用都是使函数能够在不同的对象上下文中运行。call方法和apply方法的作用类似,都是立即执行一个函数,并改变函数中this指向。bind方法和call、apply方法的作用也类似,都是改变函数中this指向。不同之处在于bind方法不会立即执行函数,而是返回一个新的函数,需要再次调用才能执行。

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

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

相关文章

Web课程学习笔记--JavaScript数据类型和数据结构

JavaScript 数据类型和数据结构 编程语言都具有内建的数据结构,但各种编程语言的数据结构常有不同之处。本文试图列出 JavaScript 语言中内建的数据结构及其属性,它们可以用来构建其他的数据结构;同时尽可能的描述与其他语言的不同之处 动态…

学习通考试怎么搜题找答案? #学习方法#微信#其他

大学生必备的做题、搜题神器,收录上万本教材辅助书籍,像什么高数、物理、计算机、外语等都有,资源十分丰富。 1.菜鸟教程 菜鸟教程是一个完全免费的编程学习软件。 它免费提供了HTML / CSS 、JavaScript 、服务端、移动端、XML 教程、http…

HCIA--NAT实验

1. 划分网段,配置接口IP地址,内网启用OSPF协议,并配置一对一的NAT: AR1配置: [Huawei]int g0/0/0 [Huawei-GigabitEthernet0/0/0]ip add 10.1.1.1 24 [Huawei-GigabitEthernet0/0/0]int g0/0/1 [Huawei-GigabitEther…

eeeeeeeeeeeeeeeeee

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 磁盘满的本质分析 专栏:《Linux从小白到大神》 | 系统学习Linux开发、VIM/GCC/GDB/Make工具…

特征工程:数据平衡

目录 一、前言 二、正文 Ⅰ.基于过采样算法 Ⅱ.基于欠采样算法 Ⅲ..基于过采样和欠采样的综合算法 三、结语 一、前言 大多数情况下,使用的数据集是不完美的,会出现各种各样的问题,尤其针对分类问题的时候,会出现类别不平衡的…

《MySQL 简易速速上手小册》第5章:高可用性和灾难恢复(2024 最新版)

文章目录 5.1 构建高可用性 MySQL 解决方案5.1.1 基础知识5.1.2 重点案例:使用 Python 构建高可用性的电子商务平台数据库5.1.3 拓展案例 5.2 数据备份策略和工具5.2.1 基础知识5.2.2 重点案例:使用 Python 实现 MySQL 定期备份5.2.3 拓展案例 5.3 灾难恢…

【5G NR】【一文读懂系列】移动通讯中使用的信道编解码技术-卷积码原理

目录 一、引言 二、卷积编码的发展历史 2.1 卷积码的起源 2.2 主要发展阶段 2.3 重要里程碑 三、卷积编码的基本概念 3.1 基本定义 3.2 编码器框图 3.3 编码多项式 3.4 网格图(Trellis)描述 四、MATLAB示例 一、引言 卷积编码,作为数字通信领域中的一项…

redis双写一致

redis双写一致,指的是redis缓存与mysql数据同步 双写一致常见方案有很多: 同步双写:更新完mysql后立即同时更新redis mq同步:程序在更新完mysql后,投递消息到中间键mq,一个程序监听mq,获得消…

用EXCEL从地址(上海)中提取各区(浦东新区等区)信息

背景: 朋友工作需要经常用EXCEL把各上海用户收货地址中的区提取出来,之前一直手动处理,希望我帮忙用EXCEL公式直接提取处理。 数据样式: 中国上海市浦东新区A小区 上海徐汇区B小区 中国,上海,浦东新区&a…

Android:Volley框架使用

3.15 Volley框架使用 Volley框架主要作为网络请求,图片加载工具。当应用数据量小、网络请求频繁,可以使用Volley框架。 框架Github地址:https://github.com/google/volley Volley框架的简单使用,创建项目Pro_VolleyDemo。将Github上下载Volley框架源代码,volley-master.zi…

【05】C++ 内存管理

文章目录 🌈 Ⅰ C 内存分布🌈 Ⅱ C 内存管理方式1. new 和 delete 操作内置类型2. new 和 delete 操作自定义类型 🌈 Ⅲ operator new 和 operator delete🌈 Ⅳ new 和 delete 的实现原理1. 内置数据类型2. 自定义数据类型 &#…

leetcode 3027. 人员站位的方案数 II【离散化前缀和+枚举】

原题链接:3027. 人员站位的方案数 II 题目描述: 给你一个 n x 2 的二维数组 points ,它表示二维平面上的一些点坐标,其中 points[i] [xi, yi] 。 我们定义 x 轴的正方向为 右 (x 轴递增的方向)&#x…

架构之模板方法等模式的使用

目录 一、程序编写背景 二、编程思路讲解 - 类图 - 实现逻辑 - 工厂模式 - 模板方法模式 接口类(代码)抽象类(代码)具体实现类(代码)工厂类(代码)注册类(代码&…

租用海外服务器丢包是什么情况?

在当今的互联网时代,海外服务器租用已经成为了许多企业和个人的选择。然而,在使用海外服务器的过程中,有时会出现丢包的情况,这给用户带来了不小的困扰。那么,租用海外服务器丢包是什么情况呢?本文将对此进…

【Python】Mac 本地部署 stable-diffusion

其实要在本地部署 stable-diffusion 不难,只要有“魔法”一切都水到渠成,如下图: (base) MacBook-Pro python % git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui Cloning into stable-diffusion-webui... remote: Enu…

开发JSP应用程序

开发JSP应用程序 问题陈述 TecknoSoft Pvt Ltd.公司的首席技术官(CTO)John Barrett将创建一个应用程序的任务委托给了开发团队,该应用程序应在客户访问其账户详细信息前验证其客户ID和密码。客户ID应是数字形式。John希望如果所输入的客户ID或密码不正确,应向客户显示错误…

2.7日学习打卡----初学RabbitMQ(二)

2.7日学习打卡 JMS 由于MQ产品很多,操作方式各有不同,于是JAVA提供了一套规则 ——JMS,用于操作消息中间件。JMS即Java消息服务 (JavaMessage Service)应用程序接口,是一个Java平台中关于面 向消息中间件的…

ssm+vue的医药垃圾分类管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。

演示视频: ssmvue的医药垃圾分类管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结…

在本地运行大型语言模型 (LLM) 的六种方法(2024 年 1 月)

一、说明 (开放)本地大型语言模型(LLM),特别是在 Meta 发布LLaMA和后Llama 2,变得越来越好,并且被越来越广泛地采用。 在本文中,我想演示在本地(即在您的计算机上&#x…

Android 粒子喷泉动效

一、前言: 在学习open gl es实现动效的时候,打算回顾了一下用普通的2D坐标系实现粒子效果和 open gl 3d 坐标系的区别,以及难易程度,因此本篇以Canvas 2D坐标系实现了一个简单的demo。 粒子动效原理: 粒子动效本质上…