[重点]call、apply和bind的区别以及源码解析

2023-11-05

前言:在前端面试中,最常见的面试题

  1. this的指向问题?
  2. 如何改变this指向?
  3. call、apply和bind的区别以及源码解析?

如果面试官问到this的指向问题,那么你去引导面试官,让他问你如何改变this指向,call、apply和bind的区别以及源码解析,这样主动权就掌握在自己的手中,自古深情留不住,总是套路得人心,或者你回答中提到改变this指向及call、apply和bind的区别以及源码解析,是不是就可以给你自己加分了。嘻嘻~

我们知道在javascript中call和apply以及bind都可以改变this指向,彼此之间有什么区别呢?那么它们是怎么实现的呢?
首先,我们先说下call、apply和bind的用法

一、call、apply和bind的用法

  • call(this,…arguments);
  • apply(this,[arguments]);
  • bind(this, …arguments)(…newarguments);

再聊聊区别

二、区别

  • call() 和apply()的第一个参数相同,就是指定的对象。这个对象就是该函数的执行上下文。

  • call()和apply()的区别就在于,两者之间的参数。call()在第一个参数之后的 后续所有参数就是传入该函数的值。apply() 只有两个参数,第一个是对象,第二个是数组,这个数组就是该函数的参数。

  • bind() 方法和前两者不同在于:bind()方法会返回执行上下文被改变的函数而不会立即执行,而前两者是直接执行该函数。他的参数和call()相同。

最后看看源码解析

三、源码解析

1、call()源码解析

Function.prototype.myCall = function(context) {
    if (typeof this !== 'function') {
        throw new TypeError('Error')
    }
    context = context || window
    // 谁调用call方法,this就指向谁
    context.fn = this  
    // 去掉所有参数中第一参数(指定的对象)
    const args = [...arguments].slice(1)
    const result = context.fn(...args)
    delete context.fn
    return result
}

以下是对call()实现的分析:

  1. 首先 context 为可选参数,如果不传的话默认上下文为 window;
  2. 接下来给 context 创建一个 fn 属性,并将值设置为需要调用的函数,即this;
  3. 因为 call 可以传入多个参数作为调用函数的参数,所以需要将参数剥离出来,去掉所有参数中第一参数(指定的对象);
  4. 然后调用函数并将对象上的函数fn删除;

2、apply()源码解析

apply 的实现和 call 类似,区别在于对参数的处理。

Function.prototype.apply = function (context) {
    if (typeof this !== 'function') {
        throw new TypeError('Error')
    }
    context = context || window
    context.fn = this
    let result
    // 处理参数和 call 有区别,apply只有两个参数,第一个是对象,第二个是数组
    if (arguments[1]) {
        result = context.fn(...arguments[1])
    } else {
        result = context.fn()
    }
    delete context.fn
    return result
}

以下是对apply()实现的分析:

  1. 首先 context 为可选参数,如果不传的话默认上下文为 window;
  2. 接下来给 context 创建一个 fn 属性,并将值设置为需要调用的函数,即this;
  3. apply第二个参数是数组,这是apply和call的区别,区别在于对参数的处理;
  4. 然后调用函数并将对象上的函数fn删除;

3、bind()源码解析

bind 的实现对比其他两个函数略微地复杂了一点,因为 bind 需要返回一个函数,需要判断一些边界问题,以下是 bind 的实现

Function.prototype.bind = function(context) {
    if (typeof this !== 'function') {
        throw new TypeError('Error')
    }
    const _this = this
    const args = [...arguments].slice(1)
    // 返回一个函数
    return function F() {
        // 因为返回了一个函数,我们可以 new F(),所以需要判断
        if (this instanceof F) {
            // 忽略传入的this
            return new _this(...args, ...arguments)
        }
        // 直接调用,将两边的参数拼接起来
        return _this.apply(context, args.concat(...arguments))
    }
}

以下是对bind()实现的分析:

  1. 首先 context 为可选参数,如果不传的话默认上下文为 window;
  2. 接下来给 context 创建一个 fn 属性,并将值设置为需要调用的函数,即this;
  3. bind和call参数相同,可以传入多个参数作为调用函数的参数,所以需要将参数剥离出来,去掉所有参数中第一参数(指定的对象);
  4. bind 返回了一个函数,对于函数来说有两种方式调用,一种是直接调用,一种是通过 new的方式;
  5. 对于直接调用来说,这里选择了 apply 的方式实现,但是对于参数需要注意以下情况:因为 bind 可以实现类似这样的代码
    f.bind(obj, 1)(2)所以我们需要将两边的参数拼接起来,于是就有了这样的实现 args.concat(…arguments);
  6. 通过 new 的方式,对于 new 的情况来说,不会被任何方式改变 this,所以对于这种情况我们需要忽略传入的this;

it’s over.

结语:感谢您的阅读,希望此篇文章对您有所帮助,以上有不足的地方,欢迎指正呀!!!文章有些内容来自 前端面试之道,如有侵权,请联系作者删除,小册很不错哟~!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[重点]call、apply和bind的区别以及源码解析 的相关文章

随机推荐

  • 计算机网络重点知识解析(2)

    计算机网络重点知识的总结 接上一篇文章 文章目录 HTTP协议 HTTP协议简介 HTTP请求响应的步骤 HTTP常见状态码 GET请求和POST请求 Cookie和Session HTTPS协议 Socket 简介 总结 HTTP协议 h
  • Mybatis的xxxMapper.xml文件节点的statementType属性说明

    概述 在xxxMapper xml文件中可以使用statementType标记使用什么的对象操作SQL语句 说明 StatementType取值说明 1 STATEMENT 直接操作sql 不进行预编译 获取数据 gt gt Stateme
  • 给模型的模块添加触摸点击等交互事件

    给camera添加组件 Component Event Physics Raycaster 给模型添加碰撞体 选中要交互的模块 Component Physics Box Collider 调整collider的size直到合适 最后同时给
  • Windows下python(conda)加载spatialite模板

    如果在python调用spatialite的函数 报错no such function MBRContains ST Contains python则需要加载spatialite扩展 共两步 1 先在The Gaia SINS federa
  • java创建request_java ->HttpServletRequest

    HttpServletRequest HttpServletRequest概述 我们在创建Servlet时会覆盖service 方法 或doGet doPost 这些方法都有两个参数 一个为代表请求的request和代表响应response
  • [JSP暑假实训] 三.MySQL数据库基本操作及Servlet网站连接显示数据库信息

    本系列文章是作者暑假给学生进行实训分享的笔记 主要介绍MyEclipse环境下JSP网站开发 包括JAVA基础 网页布局 数据库基础 Servlet 前端后台数据库交互 DAO等知识 前一篇文章讲解了MyEclipse环境下创建JSP注册表
  • Java锁性能提高(锁升级)机制总结

    锁的使用很难避免 如何尽量提高锁的性能就显得比较重要了 锁偏向 所谓的偏向锁是指在对象实例的Mark Word 说白了就是对象内存中的开头几个字节保留的信息 如果把一个对象序列化后明显可以看见开头的这些信息 为了在线程竞争不激烈的情况下 减
  • 机器学习极好的入门学习视频推荐

    首先说明本人最早看的机器学习视频是吴恩达的机器学习后来发现并不适合我 如果你以前了解过一些算法 不妨看看我以下推荐的视频 对于一点都不了解机器学习的小白 那就更要看我推荐的视频了 当然吴恩达的机器学习也很好 但是相信我 看下面我推荐的视频是
  • wikiextractor 提取维基百科语料报错的解决办法

    我提取维基百科语料的时候 刚开始使用的wikiextractor 后来发现总是报错 于是就没有用了 由于很多人都在问我是怎么提取的 现在把代码公布下 代码不是我写的 是从一个网站找到的 由于太久了 忘记了网站的地址 就没办法贴原网址了 如果
  • 登录验证码由servlet实现

    简单的登录验证码由servlet实现 创建包util 类ImageServlet package util import javax imageio ImageIO import javax servlet ServletException
  • 程序员如何优雅地解决线上问题?

    身为一个程序员 遇到线上问题那都是家常便饭的事儿 如果你在深夜看到一群同事围在一起 他们是在共同探讨什么哲学问题么 非也 他们一定是遇到了线上BUG 线上问题只要影响到了核心业务流程那便是事故 所以一旦事故发生 无论你在约会 还是周末打游戏
  • 练习- Java类和对象之构造方法与对象创建之计算数学中的分数值

    任务描述 本关任务 跟据键盘输入的分子和分母求出该分数的值 其中第一次输入的值为分子的值 第二次输入的值为分母的值 两次的值均为 int 型 任务 跟据键盘输入的分子和分母求出该分数的值 其中第一次输入的值为分子的值 第二次输入的值为分母的
  • C++ map (不影响map结构) 按照 插入顺序排序 (**)

    C map 不影响map结构 按照 插入顺序排序 C 实现的支持插入顺序的高效map 第三方的库 要点 1 Qt 设计的初期 只是一个自成系统的图形框架 它的功能只是为了满足设计 ui之用 虽然后来不断地扩大了使用的范围 使其有向 全功能的
  • centos7 x11vnc配置

    shishi将文件夹放入 opt目录下面 安装x11vnc cd opt x11vnc1 rpm ivh rpm 配置x11vnc cp opt x11vnc1 x11vnc service etc systemd system 文件内容如
  • Fiddler手机抓包

    本文转载自 Fiddler手机抓包 机智的老猫咪 博客园 Fiddler是一款安装在PC上的抓包软件 它不仅可以对pc上的程序进行抓包 也可以对手机上的程序进行抓包 下面说下抓取手机程序的步骤 一 PC端设置 1 PC上Fiddler抓取H
  • 【放苹果】m个苹果放到n个盘子中

    m个相同的苹果 放在n个相同的盘子中 由于相同 使用排列组合的方法不好处理 这里选用递归调用的方式解决问题 8个苹果 放在3个盘子里 8个苹果 放在2个盘子 5个苹果 放在2个盘子 每盘已经放入1个苹果 2个苹果 放在2个盘子里 每盘已经放
  • 设置linux防火墙的的脚本,Linux开启防火墙并设置策略脚本

    bash bash 现有规则全部注销 iptables P INPUT ACCEPT iptables F 全部进入端口禁止 iptables P INPUT DROP 开启ping和snmp iptables A INPUT i lo j
  • uniapp封装promise接口

    uniapp封装promise接口 uni app题拱了uni requet 方法 发起网络请求 首先在根目录里创建一个request文件夹 在里面创建request js文件 在文件里编写发起网络请求的代码 在全局main js中配置 在
  • vue项目使用vue-quill-editor,光标位置控制(已解决)

    查了网上很多资料使用 都没有解决 故记录在此 全局引入 import Vue from vue import VueQuillEditor from vue quill editor require styles import quill
  • [重点]call、apply和bind的区别以及源码解析

    前言 在前端面试中 最常见的面试题 this的指向问题 如何改变this指向 call apply和bind的区别以及源码解析 如果面试官问到this的指向问题 那么你去引导面试官 让他问你如何改变this指向 call apply和bin