js手写call、bind、apply

目录

  • call与apply
    • apply
  • bind

callapplybind有两种实现方式,第一种是隐式绑定,第二种是通过new
无论是通过隐式绑定实现还是通过new实现,核心都是针对this的绑定规则
具体关于this的绑定规则可以看我这一篇博客
this绑定规则

call与apply

我们先回想一下call的使用方法

function foo() {
    return this
}
console.log(foo.call({ name: 18 }))

结果
接下来让我们一步步实现

首先call是一个实例方法,所以我们的myCall也需要设置在Function.prototype

Function.prototype.myCall = function () {
}

call会传入多个参数,第一个是被绑定的this,剩下的是函数调用的参数列表

Function.prototype.myCall = function (that, ...args) {
}

接下来我们就需要在myCall中调用函数,我们可以通过this()的形式直接调用函数,因为foo.myCall本身就是一种隐式绑定
因为函数可能会有返回结果,所以我们需要将返回结果给返回出去

Function.prototype.myCall = function (that, ...args) {
    const value = this(...args)
    return value
}

接下来我们需要将thisthis绑定到我们指定的that身上,我们可以在that上新增一个属性,用这个属性来存放函数
然而我们并不能确定that身上拥有哪些属性,没有哪些属性,如果我们的函数存放到了原有的属性上则可能会发生错误,这表明了我们无法确定存放函数的属性名
幸运的是ES6中推出了新的基本类型Symbol,使用它我们可以很轻松的得到唯一的属性名
具体关于Symbol可以看我这篇文章
Symbol

Function.prototype.myCall = function (that, ...args) {
    const fn = Symbol("fn")
    that[fn] = this
    const value = that[fn](...args)
    return value
}

我们并不希望用户能在函数中访问到我们的fn,在fn运行完之后我们也需要将fn删除,所以我们需要使用属性描述符来配置fn
具体属性描述符可以看我这篇文章
属性描述符

Function.prototype.myCall = function (that, ...args) {
    const fn = Symbol("fn")
    Object.defineProperty(that, fn, {
        value: this,
        enumerable: false,
        configurable: true
    })
    const value = that[fn](...args)
    delete that[fn]
    return value
}

最后我们还需要针对that来判断一下,如果传入的thatnull或者undefined,我们需要将函数绑定到window,如果传入的不是一个对象,我们就需要将它装箱

Function.prototype.myCall = function (that, ...args) {
    that = (typeof that === "null" || typeof that === "undefined") ? window : Object(that)
    const fn = Symbol("fn")
    Object.defineProperty(that, fn, {
        value: this,
        enumerable: false,
        configurable: true
    })
    const value = that[fn](...args)
    delete that[fn]
    return value
}

最后我们来测试一下

function foo() {
    return this
}
console.log(foo.myCall({ name: 18 }))

结果

apply

applycall类似,只有在传入参数上不一样,call是将函数参数一个一个传入,而apply是将参数合为一个数组传入

Function.prototype.myApply = function (that, args) {
    that = (typeof that === "null" || typeof that === "undefined") ? window : Object(that)
    const fn = Symbol("fn")
    Object.defineProperty(that, fn, {
        value: this,
        enumerable: false,
        configurable: true
    })
    const value = that[fn](...args)
    delete that[fn]
    return value
}

bind

bind和以上两个很类似,区别在于bind返回一个函数,这个函数不能再通过callapply来更改this指向

Function.prototype.myBind = function (that, ...args) {
    that = (typeof that === "null" || typeof that === "undefined") ? window : Object(that)
    const fn = Symbol("fn")
    return (...args2) => {
        const allArgs = args.concat(args2)
        Object.defineProperty(that, fn, {
            value: this,
            enumerable: false,
            configurable: false
        })
        const value = that[fn](...allArgs)
        return value
    }
}

需要注意的是,我们返回的函数不能删除fn,如果删除了fn的话运行会报错,因为找不到这个属性
如果在返回的函数上进行call或者apply也不会更改新函数的this,因为无论是call还是apply都是在原先函数上套了一个新函数,由新函数隐式调用原函数,但经过bind绑定过后的函数被一个新函数包裹,经历了两次调用,所以原函数的this指向不会丢失
测试结果

function foo() {
    return this
}
const newFoo = foo.myBind({ name: 18 })
console.log(newFoo())
console.log(newFoo.myCall(window))
console.log(newFoo.apply(window))

结果

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【热议】硕士和读博士洗碗区别的两大理论

::: block-1 “时问桫椤”是一个致力于为本科生到研究生教育阶段提供帮助的不太正式的公众号。我们旨在在大家感到困惑、痛苦或面临困难时伸出援手。通过总结广大研究生的经验,帮助大家尽早适应研究生生活,尽快了解科研的本质。祝一切顺利!—…

【软件测试基础】概述篇(持续更新中)

《 软件测试基础持续更新中》 这一章,是每一名软件测试工程师必须要掌握的常识! 1、软件测试的目的:提高软件质量 和 确保软件满足用户需求。 2、软件测试的概念:使用人工或自动手段来运行或测试某个系统的过程,目的…

品牌差异化战略:Kompas.ai如何打造独特的内容声音

在当今竞争激烈的商业环境中,品牌差异化已成为企业获取市场优势的关键策略。一个鲜明的品牌形象和独特的内容声音不仅能够帮助企业吸引目标客户,还能够在消费者心中建立起独特的地位。本文将深入探讨品牌差异化的重要性,分析Kompas.ai如何帮助…

SL3037内置MOS管 耐压60V降压恒压芯片 降12V或降24V 电路简单

SL3037B是一款内置功率MOSFET的单片降压型开关模式转换器,具有以下特点: 1. 高效率:采用开关式降压技术,仅在需要调节输出电压时才会消耗能量,从而提高了整体的效率。 2. 稳定性好:通过精确的内部电路设计…

数睿通2.0版本升级:探索数据血缘的奥秘

引言 数睿通 2.0 迎来了 4 月份的更新,该版本更新了许多用户期望的数据血缘模块,把原来外链跳转 neo4j 页面改为自研页面,方便后期的二次开发完善,此外,新版本摒弃了 neo4j 的血缘数据存储方案,一来是因为…

接口压力测试 jmeter--进阶篇(三)

一、数据实时监控JMeterGrafanaInfluxdb (mac)性能监控平台搭建JMeterGrafanaInfluxdb 优点: 1.实时 2.美观 3.能够存储和对比 原理: 1.运行jmeter时会吧数据写入到influxdb 2.influxdb实时存储执行的结果 3.grafana链接.influxd…

基于 Flexbox 的纯 CSS 框架:兼容性好、文档丰富 | 开源日报 No.232

jgthms/bulma Stars: 48.3k License: MIT bulma 是基于 Flexbox 的现代 CSS 框架。 基于 Flexbox 技术。提供快速安装方式,支持 NPM、Yarn 和 Bower。仅包含 CSS 文件,没有 JavaScript 部分。兼容性良好,在主流浏览器上运行良好。提供丰富的…

工作中常用的5种加密算法

背景 最近,项目中做了一些安全性要求的整改。而加密是使用过程中常用的手段之一。这里简单的整理下,希望对小伙伴有帮助。 使用场景 加密是一种将原始信息(明文)转换成难以被直接理解的形式(密文)的过程…

信息收集

信息收集 域名的相关知识 域名的技术指的是一个域名由多少级组成,域名的各个级别被“.”分开,简而言之,有多少个点就是几级域名 顶级域名:.com(商)、.edu(教)、.gov(政)、.mil(军) 一级域名:qq.com 二级域名&#xf…

Python--容器、面向对象

一、容器类型(下) 重点学习容器的定义 常用操作的建议 跟着课堂把代码写一遍即可,混个脸熟,后面现用现查 增、删、改、查:重点掌握 查 字符串、元组:只能查,不能改 1.1 字符串str 1.1.1 字符串基本语法 1.1.2 字…

外呼系统出海注意事项

外呼系统在出海过程中需要注意多个方面,以确保系统的有效运行和合规性。以下是一些关键的注意事项: 一、市场调研与目标定位: 在出海前,深入调研目标市场的行业趋势、消费者偏好、文化背景和竞争态势。这有助于企业更好地了解市场…

基于麻雀搜索算法-BP神经网络SSA-BP回归预测

文章目录 效果一览文章概述订阅专栏只能获取一份代码部分源码参考资料效果一览 文章概述 基于麻雀搜索算法-BP神经网络SSA-BP回归预测 订阅专栏只能获取一份代码 部分源码 %------

几种Python处理Excel数据的方法!

第一种方法: 电子表格格式 我们在日常工作中常常见到各种后缀的电子表格,例如最常见的xlsx以及较为常见的csv、xls等格式的表格。同样是电子表格,它们之间有什么区别吗? • xls为Excel早期表格格式。 xls格式是Excel2003版本及…

TDengineGUI无法连接TDengine

可能是TDengineGUI本身的问题,直接下载可执行文件即可 下载地址:Release 1.0.3 ericyangpan/TDengineGUI (github.com) 还有可能是你的6041端口没开注意检查 可在TDengine文件夹下直接执行 systemctl start taosadapter 也可以点击 taosadapter.exe …

管理者如何在团队里讨论敏感话题

在团队中处理不便讨论的敏感话题可能会令人不适,但如果无视问题,它们会不知不觉地积聚起来,影响士气。 随着团队地理上越来越分散以及线上沟通增多,感知到团队间的不适或提出敏感话题变得更加困难。但是,忽略这些难以…

企业组网的作用有哪些?SD-WAN有什么优势?

在信息化的时代,企业组网建设逐渐成为提升企业竞争力、实现业务高效运行的关键,它能够为企业在信息传输、资源共享、远程办公等方面提供强大的支持。接下来,本文为大家详细介绍企业网络组网的意义,以及为大家推荐热门的网络解决方…

JVM (Micrometer)监控SpringBoot(AWS EKS版)

问题 怎样使用JVM (Micrometer)面板&#xff0c;监控Spring&#xff1f;这里不涉及Prometheus和Grafana&#xff0c;重点介绍与Micrometer与Springboot&#xff0c;k8s怎样集成。 pom.xml 引入依赖&#xff0c;如下&#xff1a; <properties><micrometer.version&…

【缓存服务】⭐️自定义实现一个简易的数据缓存

目录 &#x1f378;前言 &#x1f37b;手写缓存服务 &#xff08;1&#xff09;缓存实体类 &#xff08;2&#xff09;缓存工具类 &#xff08;3&#xff09;测试缓存服务 &#x1f377;已有的缓存工具 &#x1f379;章末 &#x1f378;前言 俗话说 有轮子不用 就是玩 开个…

推荐3个视频转文字的工具

如果是长视频转文字的话&#xff0c;我会推荐你三个专业的能够将视频文字提取出来的工具&#xff0c;操作无门槛&#xff0c;转换出的文字准确率高&#xff0c;可以直接导出文字。 1.一键识别王 https://www.xunjiepdf.com/yijianshibiewang 专业的图片文字识别软件&#xff0…

AQ6370C YOKOGAWA 横河 光谱分析仪 简述

YOKOGAWA AQ6370C是一款高性能的光谱分析仪&#xff0c;具有世界一流的光学性能。它的波长范围为600至1700nm&#xff0c;能够提供高波长精度0.01nm和高波长分辨率0.02nm。此外&#xff0c;AQ6370C具备大动态范围78dB&#xff08;典型值&#xff09;和宽功率量程20~-90dBm&…